updated on Thu Jan 19 20:01:47 UTC 2012
[aur-mirror.git] / nvidia-71xx-ice / NVIDIA_kernel-96.43.05-2290218.diff.txt
blob0dfcfd5aa9c89b4b4ddb9f6e4ddf8877598ce31e
1 diff -ru usr/src/nv/Makefile.kbuild usr/src/nv.2305230/Makefile.kbuild
2 --- usr/src/nv/Makefile.kbuild  2008-01-21 11:48:11.000000000 -0800
3 +++ usr/src/nv.2305230/Makefile.kbuild  2008-03-18 12:55:25.461856977 -0700
4 @@ -176,6 +176,7 @@
5         vmap \
6         signal_struct \
7         agp_backend_acquire \
8 +       set_pages_uc \
9         change_page_attr \
10         pci_get_class \
11         sysctl_max_map_count \
12 diff -ru usr/src/nv/conftest.sh usr/src/nv.2305230/conftest.sh
13 --- usr/src/nv/conftest.sh      2008-01-21 11:48:11.000000000 -0800
14 +++ usr/src/nv.2305230/conftest.sh      2008-03-18 12:55:28.782046180 -0700
15 @@ -100,6 +100,32 @@
16              fi
17          ;;
19 +        set_pages_uc)
20 +            #
21 +            # Determine if the set_pages_uc() function is present.
22 +            #
23 +            echo "#include <linux/autoconf.h>
24 +            #include <asm/cacheflush.h>
25 +            void conftest_set_pages_uc(void) {
26 +                set_pages_uc();
27 +            }" > conftest$$.c
29 +            $CC $CFLAGS -c conftest$$.c > /dev/null 2>&1
30 +            rm -f conftest$$.c
32 +            if [ -f conftest$$.o ]; then
33 +                rm -f conftest$$.o
34 +                echo "#undef NV_SET_PAGES_UC_PRESENT" >> conftest.h
35 +                return
36 +            else
37 +                echo "#ifdef NV_CHANGE_PAGE_ATTR_PRESENT" >> conftest.h
38 +                echo "#undef NV_CHANGE_PAGE_ATTR_PRESENT" >> conftest.h
39 +                echo "#endif"                             >> conftest.h
40 +                echo "#define NV_SET_PAGES_UC_PRESENT"    >> conftest.h
41 +                return
42 +            fi
43 +        ;;
45          change_page_attr)
46              #
47              # Determine if the change_page_attr() function is
48 @@ -124,7 +150,9 @@
49                  rm -f conftest$$.o
50                  return
51              else
52 +                echo "#ifndef NV_SET_PAGES_UC_PRESENT"     >> conftest.h
53                  echo "#define NV_CHANGE_PAGE_ATTR_PRESENT" >> conftest.h
54 +                echo "#endif"                              >> conftest.h
55                  return
56              fi
57          ;;
58 @@ -501,6 +529,8 @@
59                  return
60              fi
62 +            rm -f conftest$$.o
64              echo "#include <linux/autoconf.h>
65              #include <linux/interrupt.h>
66              irq_handler_t conftest_isr;
67 diff -ru usr/src/nv/nv-linux.h usr/src/nv.2305230/nv-linux.h
68 --- usr/src/nv/nv-linux.h       2008-01-21 11:48:11.000000000 -0800
69 +++ usr/src/nv.2305230/nv-linux.h       2008-03-18 12:57:26.340745475 -0700
70 @@ -19,8 +19,8 @@
71  #include <linux/utsname.h>
74 -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0)
75 -#  error This driver does not support pre-2.4 kernels!
76 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 7)
77 +#  error This driver does not support 2.4 kernels older than 2.4.7!
78  #elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
79  #  define KERNEL_2_4
80  #elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
81 @@ -51,6 +51,10 @@
82  #include <linux/modversions.h>
83  #endif
85 +#if defined(KERNEL_2_4) && !defined(EXPORT_SYMTAB)
86 +#define EXPORT_SYMTAB
87 +#endif
89  #include <linux/kernel.h>
90  #include <linux/module.h>
92 @@ -98,6 +102,7 @@
94  #include <linux/spinlock.h>
95  #include <asm/semaphore.h>
96 +#include <linux/completion.h>
97  #include <linux/highmem.h>
99  #ifdef CONFIG_PROC_FS
100 @@ -118,8 +123,12 @@
101  #endif
103  #if defined(CONFIG_KGDB)
104 +#if defined(NV_OLD_MM_KGDB_BREAKPOINT_PRESENT)
105 +#include <asm/kgdb.h>
106 +#else
107  #include <linux/kgdb.h>
108  #endif
109 +#endif
111  #if defined (CONFIG_AGP) || defined (CONFIG_AGP_MODULE)
112  #define AGPGART
113 @@ -516,19 +525,16 @@
114  #define NV_KMEM_CACHE_ALLOC(ptr, kmem_cache, type)              \
115      {                                                           \
116          (ptr) = kmem_cache_alloc(kmem_cache, GFP_KERNEL);       \
117 -        KM_ALLOC_RECORD(ptr, sizeof(type), "km_cache_alloc");   \
118      }
120  #define NV_KMEM_CACHE_FREE(ptr, type, kmem_cache)               \
121      {                                                           \
122 -        KM_FREE_RECORD(ptr, sizeof(type), "km_cache_free");     \
123          kmem_cache_free(kmem_cache, ptr);                       \
124      }
126 -#if defined(NV_SG_MAP_BUFFERS) /* Linux/x86-64, only */
127  #if defined(NV_VMAP_PRESENT)
128  #if (NV_VMAP_ARGUMENT_COUNT == 2)
129 -#define NV_VMAP(ptr, pages, count, cached)                              \
130 +#define NV_VMAP_KERNEL(ptr, pages, count, prot)                         \
131      {                                                                   \
132          (ptr) = (unsigned long)vmap(pages, count);                      \
133          VM_ALLOC_RECORD((void *)ptr, (count) * PAGE_SIZE, "vm_vmap");   \
134 @@ -537,26 +543,35 @@
135  #ifndef VM_MAP
136  #define VM_MAP  0
137  #endif
138 -#define NV_VMAP(ptr, pages, count, cached)                              \
139 +#define NV_VMAP_KERNEL(ptr, pages, count, prot)                         \
140      {                                                                   \
141 -        pgprot_t __prot = (cached) ? PAGE_KERNEL : PAGE_KERNEL_NOCACHE; \
142 -        (ptr) = (unsigned long)vmap(pages, count, VM_MAP, __prot);      \
143 +        (ptr) = (unsigned long)vmap(pages, count, VM_MAP, prot);        \
144          VM_ALLOC_RECORD((void *)ptr, (count) * PAGE_SIZE, "vm_vmap");   \
145      }
146  #else
147  #error "NV_VMAP_ARGUMENT_COUNT value unrecognized!"
148  #endif
149  #else
150 +#if defined(NV_SG_MAP_BUFFERS)
151  #error "NV_VMAP() undefined (vmap() unavailable)!"
152 +#endif
153  #endif /* NV_VMAP_PRESENT */
155 -#define NV_VUNMAP(ptr, count)                                           \
156 +#define NV_VUNMAP_KERNEL(ptr, count)                                    \
157      {                                                                   \
158 -        VM_FREE_RECORD((void *)ptr, (count) * PAGE_SIZE, "vm_vmap");    \
159 +        VM_FREE_RECORD((void *)ptr, (count) * PAGE_SIZE, "vm_vunmap");  \
160          vunmap((void *)(ptr));                                          \
161      }
163 -#endif /* NV_SG_MAP_BUFFERS */
164 +#define NV_VMAP(addr, pages, count, cached)                             \
165 +    {                                                                   \
166 +        pgprot_t __prot = (cached) ? PAGE_KERNEL : PAGE_KERNEL_NOCACHE; \
167 +        void *__ptr = nv_vmap(pages, count, __prot);                    \
168 +        (addr) = (unsigned long)__ptr;                                  \
169 +    }
171 +#define NV_VUNMAP(addr, count) nv_vunmap((void *)addr, count)
174  #endif /* !defined NVWATCH */
176 @@ -764,9 +779,10 @@
178  #define NV_PGD_OFFSET(address, kernel, mm)              \
179     ({                                                   \
180 +        struct mm_struct *__mm = (mm);                  \
181          pgd_t *__pgd;                                   \
182          if (!kernel)                                    \
183 -            __pgd = pgd_offset(mm, address);            \
184 +            __pgd = pgd_offset(__mm, address);          \
185          else                                            \
186              __pgd = pgd_offset_k(address);              \
187          __pgd;                                          \
188 @@ -968,9 +984,7 @@
189  #define NV_ALLOC_TYPE_PCI      (1<<0)
190  #define NV_ALLOC_TYPE_AGP      (1<<1)
191  #define NV_ALLOC_TYPE_CONTIG   (1<<2)
192 -#define NV_ALLOC_TYPE_KERNEL   (1<<3)
193 -#define NV_ALLOC_TYPE_VMALLOC  (1<<4)
194 -#define NV_ALLOC_TYPE_VMAP     (1<<5)
195 +#define NV_ALLOC_TYPE_VMAP     (1<<3)
197  #define NV_ALLOC_MAPPING_SHIFT      16
198  #define NV_ALLOC_MAPPING(flags)     (((flags)>>NV_ALLOC_MAPPING_SHIFT)&0xff)
199 @@ -980,7 +994,6 @@
201  #define NV_ALLOC_MAPPING_AGP(flags)     ((flags) & NV_ALLOC_TYPE_AGP)
202  #define NV_ALLOC_MAPPING_CONTIG(flags)  ((flags) & NV_ALLOC_TYPE_CONTIG)
203 -#define NV_ALLOC_MAPPING_VMALLOC(flags) ((flags) & NV_ALLOC_TYPE_VMALLOC)
204  #define NV_ALLOC_MAPPING_VMAP(flags)    ((flags) & NV_ALLOC_TYPE_VMAP)
206  static inline U032 nv_alloc_init_flags(int cached, int agp, int contig, int kernel)
207 @@ -988,12 +1001,7 @@
208      U032 flags = NV_ALLOC_ENC_MAPPING(cached);
209      if (agp)    flags |= NV_ALLOC_TYPE_AGP;
210      else        flags |= NV_ALLOC_TYPE_PCI;
211 -    if (kernel) flags |= NV_ALLOC_TYPE_KERNEL; 
212 -#if defined(NV_SG_MAP_BUFFERS)
213      if (kernel && !contig) flags |= NV_ALLOC_TYPE_VMAP;
214 -#else
215 -    if (kernel && !contig) flags |= NV_ALLOC_TYPE_VMALLOC;
216 -#endif
217      if (contig && !agp) flags |= NV_ALLOC_TYPE_CONTIG;
218      return flags;
220 @@ -1067,21 +1075,24 @@
221  #define NV_ATOMIC_DEC_AND_TEST(data)    atomic_dec_and_test(&(data))
222  #define NV_ATOMIC_READ(data)            atomic_read(&(data))
224 +extern int nv_update_memory_types;
226  /*
227 - * a BUG() is triggered on early 2.6 x86_64 kernels. the underlying
228 - * problem actually exists on many architectures and kernels, but
229 - * these are the only kernels that check the condition and trigger
230 - * a BUG(). note that this is a problem of the core kernel, not an
231 - * nvidia bug (and can still be triggered by agpgart). let's avoid
232 - * change_page_attr on those kernels.
233 + * Using change_page_attr() on early Linux/x86-64 2.6 kernels may
234 + * result in a BUG() being triggered. The underlying problem
235 + * actually exists on multiple architectures and kernels, but only
236 + * the above check for the condition and trigger a BUG().
237 + *
238 + * Note that this is a due to a bug in the Linux kernel, not an
239 + * NVIDIA driver bug (it can also be triggered by AGPGART).
240 + *
241 + * We therefore need to determine at runtime if change_page_attr()
242 + * can be used safely on these kernels.
243   */
244 -#if defined(NV_CHANGE_PAGE_ATTR_PRESENT)
245 -extern int nv_use_cpa;
247 -#if defined(NVCPU_X86_64) && !defined(KERNEL_2_4) && \
248 -         (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 11))
249 -#define NV_CHANGE_PAGE_ATTR_BUG_PRESENT 1
250 -#endif
251 +#if defined(NV_CHANGE_PAGE_ATTR_PRESENT) && defined(NVCPU_X86_64) && \
252 +  !defined(KERNEL_2_4) && \
253 +  (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 11))
254 +#define NV_CHANGE_PAGE_ATTR_BUG_PRESENT
255  #endif
257  #if defined(NVCPU_X86) || defined(NVCPU_X86_64)
258 @@ -1093,7 +1104,7 @@
259   *
260   * We need to be careful to mask out _PAGE_NX when the host system
261   * doesn't support this feature or when it's disabled: the kernel
262 - * may not do this in its implementation of the  change_page_attr()
263 + * may not do this in its implementation of the change_page_attr()
264   * interface.
265   */
266  #ifndef X86_FEATURE_NX
267 diff -ru usr/src/nv/nv-vm.c usr/src/nv.2305230/nv-vm.c
268 --- usr/src/nv/nv-vm.c  2008-01-21 11:48:11.000000000 -0800
269 +++ usr/src/nv.2305230/nv-vm.c  2008-03-18 12:55:58.755754293 -0700
270 @@ -43,42 +43,40 @@
272  #endif
275 - * AMD Athlon processors expose a subtle bug in the Linux
276 - * kernel, that may lead to AGP memory corruption. Recent
277 - * kernel versions had a workaround for this problem, but
278 - * 2.4.20 is the first kernel to address it properly. The
279 - * page_attr API provides the means to solve the problem. 
280 - */
282  static inline void nv_set_page_attrib_uncached(nv_pte_t *page_ptr)
284 -#if defined(NV_CHANGE_PAGE_ATTR_PRESENT)
285 -    if (nv_use_cpa)
286 +    if (nv_update_memory_types)
287      {
288 -        struct page *page = virt_to_page(__va(page_ptr->phys_addr));
289 +#if defined(NV_SET_PAGES_UC_PRESENT)
290 +        struct page *page = NV_GET_PAGE_STRUCT(page_ptr->phys_addr);
291 +        set_pages_uc(page, 1);
292 +#elif defined(NV_CHANGE_PAGE_ATTR_PRESENT)
293 +        struct page *page = NV_GET_PAGE_STRUCT(page_ptr->phys_addr);
294          pgprot_t prot = PAGE_KERNEL_NOCACHE;
295  #if defined(NVCPU_X86) || defined(NVCPU_X86_64)
296          pgprot_val(prot) &= __nv_supported_pte_mask;
297  #endif
298          change_page_attr(page, 1, prot);
299 -    }
300  #endif
301 +    }
304  static inline void nv_set_page_attrib_cached(nv_pte_t *page_ptr)
306 -#if defined(NV_CHANGE_PAGE_ATTR_PRESENT)
307 -    if (nv_use_cpa)
308 +    if (nv_update_memory_types)
309      {
310 -        struct page *page = virt_to_page(__va(page_ptr->phys_addr));
311 +#if defined(NV_SET_PAGES_UC_PRESENT)
312 +        struct page *page = NV_GET_PAGE_STRUCT(page_ptr->phys_addr);
313 +        set_pages_wb(page, 1);
314 +#elif defined(NV_CHANGE_PAGE_ATTR_PRESENT)
315 +        struct page *page = NV_GET_PAGE_STRUCT(page_ptr->phys_addr);
316          pgprot_t prot = PAGE_KERNEL;
317  #if defined(NVCPU_X86) || defined(NVCPU_X86_64)
318          pgprot_val(prot) &= __nv_supported_pte_mask;
319  #endif
320          change_page_attr(page, 1, prot);
321 +#endif
322      }
323 -#endif /* NV_CHANGE_PAGE_ATTR_PRESENT */
326  static inline void nv_lock_page(nv_pte_t *page_ptr)
327 @@ -360,8 +358,11 @@
328  #if defined(NV_CPA_NEEDS_FLUSHING)
329      nv_execute_on_all_cpus(cache_flush, NULL);
330  #endif
331 +#if (defined(NVCPU_X86) || defined(NVCPU_X86_64)) && \
332 +  defined(NV_CHANGE_PAGE_ATTR_PRESENT)
333      global_flush_tlb();
334  #endif
335 +#endif
338  /*
339 @@ -409,11 +410,11 @@
340      nv_pte_t *page_ptr = *at->page_table;
341      unsigned int i, j, gfp_mask;
342      unsigned long virt_addr = 0, phys_addr;
343 +    struct page **pages = 0;
344  #if defined(NV_SG_MAP_BUFFERS)
345      int ret = -1;
346      nv_linux_state_t *nvl = NV_GET_NVL_FROM_NV_STATE(nv);
347      struct pci_dev *dev = nvl->dev;
348 -    struct page **pages = 0;
349  #endif
351      nv_printf(NV_DBG_MEMINFO, "NVRM: VM: nv_vm_malloc_pages: %d pages\n",
352 @@ -462,22 +463,7 @@
353          }
354  #endif
355      }
356 -    else if (NV_ALLOC_MAPPING_VMALLOC(at->flags))
357 -    {
358 -        void *virt_kptr = NULL;
359 -        at->size = at->num_pages * PAGE_SIZE;
360 -        nv_printf(NV_DBG_MEMINFO, "NVRM: VM:    vmalloc, size 0x%x\n", at->size);
361 -        NV_VMALLOC(virt_kptr, at->size, NV_ALLOC_MAPPING_CACHED(at->flags));
362 -        virt_addr = (unsigned long) virt_kptr;
363 -        if (virt_addr == 0)
364 -        {
365 -            nv_printf(NV_DBG_ERRORS,
366 -                "NVRM: nv_vm_malloc failed to allocate vmalloc memory\n");
367 -            return -1;
368 -        }
369 -    }
371 -#if defined(NV_SG_MAP_BUFFERS)
372      if (NV_ALLOC_MAPPING_VMAP(at->flags))
373      {
374          NV_KMALLOC(pages, sizeof(struct page *) * at->num_pages);
375 @@ -488,11 +474,10 @@
376              return -1;
377          }
378      }
379 -#endif
381      for (i = 0; i < at->num_pages; i++) 
382      {
383 -        if (!NV_ALLOC_MAPPING_CONTIG(at->flags) && !NV_ALLOC_MAPPING_VMALLOC(at->flags))
384 +        if (!NV_ALLOC_MAPPING_CONTIG(at->flags))
385          { 
386              NV_GET_FREE_PAGES(virt_addr, 0, gfp_mask); 
387              if (virt_addr == 0)
388 @@ -553,10 +538,10 @@
389              }
390          }
391          nv_sg_load(&page_ptr->sg_list, page_ptr);
392 +#endif
394          if (NV_ALLOC_MAPPING_VMAP(at->flags))
395              pages[i] = NV_GET_PAGE_STRUCT(page_ptr->phys_addr);
396 -#endif
398          if (!NV_ALLOC_MAPPING_CACHED(at->flags))
399              nv_set_page_attrib_uncached(page_ptr);
400 @@ -565,41 +550,21 @@
401          virt_addr += PAGE_SIZE;
402      }
404 -#if defined(NV_SG_MAP_BUFFERS)
405      if (NV_ALLOC_MAPPING_VMAP(at->flags))
406      {
407          NV_VMAP(virt_addr, pages, at->num_pages, NV_ALLOC_MAPPING_CACHED(at->flags));
408 -#if defined(KERNEL_2_4)
409 -        if (virt_addr != 0)
410 -        {
411 -            unsigned int i;
412 -            /*
413 -             * XXX Linux 2.4's vmap() increments the pages' reference counts
414 -             * in preparation for vfree(); the latter skips the calls to
415 -             * __free_page() if the pages are marked reserved, however, so
416 -             * that the underlying memory is effectively leaked when we free
417 -             * it later. Decrement the count here to avoid this leak.
418 -             */
419 -            for (i = 0; i < at->num_pages; i++)
420 -            {
421 -                if (PageReserved(pages[i]))
422 -                    atomic_dec(&pages[i]->count);
423 -            }
424 -        }
425 -#endif
426 -        NV_KFREE((void *)pages, sizeof(struct page *) * at->num_pages);
427          if (virt_addr == 0)
428          {
429              nv_printf(NV_DBG_ERRORS,
430                  "NVRM: VM: nv_vm_malloc_pages: failed to vmap pages\n");
431              goto failed;
432          }
433 +        NV_KFREE((void *)pages, sizeof(struct page *) * at->num_pages);
434          for (i = 0; i < at->num_pages; i++)
435          {
436              at->page_table[i]->virt_addr = virt_addr + i * PAGE_SIZE;
437          }
438      }
439 -#endif /* NV_SG_MAP_BUFFERS */
441      nv_vm_list_page_count(at->page_table, at->num_pages);
443 @@ -624,7 +589,7 @@
444                  nv_sg_unmap_buffer(dev, &page_ptr->sg_list, page_ptr);
445  #endif
446              nv_unlock_page(page_ptr);
447 -            if (!NV_ALLOC_MAPPING_CONTIG(at->flags) && !NV_ALLOC_MAPPING_VMALLOC(at->flags))
448 +            if (!NV_ALLOC_MAPPING_CONTIG(at->flags))
449                  NV_FREE_PAGES(page_ptr->virt_addr, 0);
450          }
451      }
452 @@ -638,16 +603,9 @@
453  #endif
454          NV_FREE_PAGES(page_ptr->virt_addr, at->order);
455      }
456 -    else if (NV_ALLOC_MAPPING_VMALLOC(at->flags))
457 -    {
458 -        page_ptr = *at->page_table;
459 -        NV_VFREE((void *) page_ptr->virt_addr, at->size);
460 -    }
462 -#if defined(NV_SG_MAP_BUFFERS)
463      if (NV_ALLOC_MAPPING_VMAP(at->flags) && pages != 0)
464 -        NV_VFREE((void *)pages, sizeof(struct page *) * at->num_pages);
465 -#endif
466 +        NV_KFREE((void *)pages, sizeof(struct page *) * at->num_pages);
468      return -1;
470 @@ -674,19 +632,17 @@
471      }
472      nv_vm_list_page_count(at->page_table, at->num_pages);
474 -#if defined(NV_SG_MAP_BUFFERS)
475      if (NV_ALLOC_MAPPING_VMAP(at->flags))
476          NV_VUNMAP((void *)at->page_table[0]->virt_addr, at->num_pages);    // undo vmap()
477 -#endif
479      for (i = 0; i < at->num_pages; i++)
480      {
481          page_ptr = at->page_table[i];
482          if (!NV_ALLOC_MAPPING_CACHED(at->flags))
483              nv_set_page_attrib_cached(page_ptr);
484 -#if defined(NV_SG_MAP_BUFFERS)
485          if (NV_ALLOC_MAPPING_VMAP(at->flags))
486              page_ptr->virt_addr = (unsigned long) __va(page_ptr->phys_addr);
487 +#if defined(NV_SG_MAP_BUFFERS)
488          if (!NV_ALLOC_MAPPING_CONTIG(at->flags))
489              nv_sg_unmap_buffer(dev, &page_ptr->sg_list, page_ptr);
490  #endif
491 @@ -701,7 +657,7 @@
492              }
493          }
494          nv_unlock_page(page_ptr);
495 -        if (!NV_ALLOC_MAPPING_CONTIG(at->flags) && !NV_ALLOC_MAPPING_VMALLOC(at->flags))
496 +        if (!NV_ALLOC_MAPPING_CONTIG(at->flags))
497              NV_FREE_PAGES(page_ptr->virt_addr, 0);
498      }
499      nv_flush_caches();
500 @@ -714,9 +670,136 @@
501  #endif
502          NV_FREE_PAGES(page_ptr->virt_addr, at->order);
503      }
504 -    else if (NV_ALLOC_MAPPING_VMALLOC(at->flags))
507 +#if defined(NV_VMAP_PRESENT) && defined(KERNEL_2_4) && defined(NVCPU_X86)
508 +static unsigned long
509 +nv_vmap_vmalloc(
510 +    int count,
511 +    struct page **pages,
512 +    pgprot_t prot
515 +    void *virt_addr = NULL;
516 +    unsigned int i, size = count * PAGE_SIZE;
518 +    NV_VMALLOC(virt_addr, size, TRUE);
519 +    if (virt_addr == NULL)
520 +    {
521 +        nv_printf(NV_DBG_ERRORS,
522 +            "NVRM: vmalloc() failed to allocate vmap() scratch pages!\n");
523 +        return 0;
524 +    }
526 +    for (i = 0; i < (unsigned int)count; i++)
527      {
528 -        page_ptr = *at->page_table;
529 -        NV_VFREE((void *) page_ptr->virt_addr, at->size);
530 +        pgd_t *pgd = NULL;
531 +        pmd_t *pmd = NULL;
532 +        pte_t *pte = NULL;
533 +        unsigned long address;
534 +        struct page *page;
536 +        address = (unsigned long)virt_addr + i * PAGE_SIZE; 
538 +        pgd = NV_PGD_OFFSET(address, 1, NULL);
539 +        if (!NV_PGD_PRESENT(pgd))
540 +            goto failed;
542 +        pmd = NV_PMD_OFFSET(address, pgd);
543 +        if (!NV_PMD_PRESENT(pmd))
544 +            goto failed;
546 +        pte = NV_PTE_OFFSET(address, pmd);
547 +        if (!NV_PTE_PRESENT(pte))
548 +            goto failed;
550 +        page = NV_GET_PAGE_STRUCT(pte_val(*pte) & PAGE_MASK);
551 +        get_page(pages[i]);
552 +        set_pte(pte, mk_pte(pages[i], prot));
553 +        put_page(page);
554 +        NV_PTE_UNMAP(pte);
555 +    }
556 +    nv_flush_caches();
558 +    return (unsigned long)virt_addr;
560 +failed:
561 +    NV_VFREE(virt_addr, size);
563 +    return 0;
566 +static void
567 +nv_vunmap_vmalloc(
568 +    void *address,
569 +    int count
572 +    NV_VFREE(address, count * PAGE_SIZE);
574 +#endif /* NV_VMAP_PRESENT && KERNEL_2_4 && NVCPU_X86 */
576 +void *nv_vmap(
577 +    struct page **pages,
578 +    int count,
579 +    pgprot_t prot
582 +    unsigned long virt_addr = 0;
583 +#if defined(NV_VMAP_PRESENT)
584 +#if defined(KERNEL_2_4) && defined(NVCPU_X86)
585 +    /*
586 +     * XXX Linux 2.4's vmap() checks the requested mapping's size against
587 +     * the value of (max_mapnr << PAGESHIFT); since 'map_nr' is a 32-bit
588 +     * symbol, the checks fails given enough physical memory. We can't solve
589 +     * this problem by adjusting the value of 'map_nr', but we can avoid
590 +     * vmap() by going through vmalloc().
591 +     */
592 +    if (max_mapnr >= 0x100000)
593 +        virt_addr = nv_vmap_vmalloc(count, pages, prot);
594 +    else
595 +#endif
596 +        NV_VMAP_KERNEL(virt_addr, pages, count, prot);
597 +#if defined(KERNEL_2_4)
598 +    if (virt_addr)
599 +    {
600 +        int i;
601 +        /*
602 +         * XXX Linux 2.4's vmap() increments the pages' reference counts
603 +         * in preparation for vfree(); the latter skips the calls to
604 +         * __free_page() if the pages are marked reserved, however, so
605 +         * that the underlying memory is effectively leaked when we free
606 +         * it later. Decrement the count here to avoid this leak.
607 +         */
608 +        for (i = 0; i < count; i++)
609 +        {
610 +            if (PageReserved(pages[i]))
611 +                atomic_dec(&pages[i]->count);
612 +        }
613      }
614 +#endif
615 +#endif /* NV_VMAP_PRESENT */
616 +    return (void *)virt_addr;
619 +void nv_vunmap(
620 +    void *address,
621 +    int count
624 +#if defined(NV_VMAP_PRESENT)
625 +#if defined(KERNEL_2_4) && defined(NVCPU_X86)
626 +    /*
627 +     * XXX Linux 2.4's vmap() checks the requested mapping's size against
628 +     * the value of (max_mapnr << PAGESHIFT); since 'map_nr' is a 32-bit
629 +     * symbol, the checks fails given enough physical memory. We can't solve
630 +     * this problem by adjusting the value of 'map_nr', but we can avoid
631 +     * vmap() by going through vmalloc().
632 +     */
633 +    if (max_mapnr >= 0x100000)
634 +        nv_vunmap_vmalloc(address, count);
635 +    else
636 +#endif
637 +        NV_VUNMAP_KERNEL(address, count);
638 +#endif /* NV_VMAP_PRESENT */
640 diff -ru usr/src/nv/nv-vm.h usr/src/nv.2305230/nv-vm.h
641 --- usr/src/nv/nv-vm.h  2008-01-21 11:48:11.000000000 -0800
642 +++ usr/src/nv.2305230/nv-vm.h  2008-03-18 12:55:54.643519951 -0700
643 @@ -11,6 +11,9 @@
644  #ifndef _NV_VM_H_
645  #define _NV_VM_H_
647 +void *   nv_vmap(struct page **, int, pgprot_t);
648 +void     nv_vunmap(void *, int);
650  int      nv_vm_malloc_pages(nv_state_t *, nv_alloc_t *);
651  void     nv_vm_free_pages(nv_state_t *, nv_alloc_t *);
653 diff -ru usr/src/nv/nv.c usr/src/nv.2305230/nv.c
654 --- usr/src/nv/nv.c     2008-01-21 11:48:11.000000000 -0800
655 +++ usr/src/nv.2305230/nv.c     2008-03-18 12:56:01.123889244 -0700
656 @@ -97,9 +97,7 @@
657  unsigned int nv_remap_limit;
658  #endif
660 -#if defined(NV_CHANGE_PAGE_ATTR_PRESENT)
661 -int nv_use_cpa = 1;
662 -#endif
663 +int nv_update_memory_types = 1;
665  static void *nv_pte_t_cache = NULL;
667 @@ -850,16 +848,13 @@
669      for (i = 0; i < 4; i++)
670      {
671 -         if (NV_PAT_ENTRY(pat1, i) == 1)
672 +         if ((i != 1) && NV_PAT_ENTRY(pat1, i) == 1)
673           {
674               nv_printf(NV_DBG_ERRORS, "NVRM: PAT index %d already configured for Write-Combining!\n", i);
675               nv_printf(NV_DBG_ERRORS, "NVRM: Aborting, due to PAT already being configured\n");
676               return 0;
677           }
678 -    }
680 -    for (i = 0; i < 4; i++)
681 -    {
682           if (NV_PAT_ENTRY(pat2, i) == 1)
683           {
684               nv_printf(NV_DBG_ERRORS, "NVRM: PAT index %d already configured for Write-Combining!\n", i + 4);
685 @@ -969,30 +964,26 @@
686  #endif /* defined(NV_BUILD_NV_PAT_SUPPORT) */
690  #if defined(NV_CHANGE_PAGE_ATTR_BUG_PRESENT)
692 -/* nv_verify_cpa_interface - determine if the change_page_attr bug is fixed
693 - * in this kernel.
695 + * nv_verify_cpa_interface() - determine if the change_page_attr() large page
696 + * management accounting bug known to exist in early Linux/x86-64 kernels
697 + * is present in this kernel.
698   *
699 - * there's really not a good way to determine if change_page_attr is fixed.
700 - * we can't really use cpa on 2.6 x86_64 kernels < 2.6.11, as if we run into
701 - * the accounting bug, the kernel will throw a BUG. this isn't 100% accurate,
702 - * as it doesn't throw a bug until we try to restore the caching attributes
703 - * of the page. so if we can track down a 4M allocation, we can mark it
704 - * uncached and see if the accounting was done correctly.
705 - * 
706 - * this is a little ugly, but the most accurate approach to determining if
707 - * this kernel is good.
708 + * There's really no good way to determine if change_page_attr() is working
709 + * correctly. We can't reliably use change_page_attr() on Linux/x86-64 2.6
710 + * kernels < 2.6.11: if we run into the accounting bug, the Linux kernel will
711 + * trigger a BUG() if we attempt to restore the WB memory type of a page
712 + * originally part of a large page.
713   *
714 - * why do we even bother? some distributions have back-ported the cpa fix to
715 - * kernels < 2.6.11. we want to use change_page_attr to avoid random corruption
716 - * and hangs, but need to make sure it's safe to do so.
717 + * So if we can successfully allocate such a page, change its memory type to
718 + * UC and check if the accounting was done correctly, we can determine if
719 + * the change_page_attr() interface can be used safely.
720   *
721 - * return values:
722 - *    0 - test passed, interface works
723 - *    1 - test failed, status unclear
724 - *   -1 - test failed, interface broken
725 + * Return values:
726 + *    0 - test passed, the change_page_attr() interface works
727 + *    1 - test failed, the status is unclear
728 + *   -1 - test failed, the change_page_attr() interface is broken
729   */
731  static inline pte_t *check_large_page(unsigned long vaddr)
732 @@ -1000,7 +991,7 @@
733      pgd_t *pgd = NULL;
734      pmd_t *pmd = NULL;
736 -    pgd = NV_PGD_OFFSET(vaddr, 1, &init_mm);
737 +    pgd = NV_PGD_OFFSET(vaddr, 1, NULL);
738      if (!NV_PGD_PRESENT(pgd))
739          return NULL;
741 @@ -1110,35 +1101,42 @@
743      return 1;
746  #endif /* defined(NV_CHANGE_PAGE_ATTR_BUG_PRESENT) */
749 -// verify that the kernel's mapping matches the requested type 
750 -// this is to protect against accidental cache aliasing problems
752 + * nv_verify_page_mappings() - verify that the kernel mapping of the specified
753 + * page matches the specified type. This is to help detect bugs in the Linux
754 + * kernel's change_page_attr() interface, early.
755 + *
756 + * This function relies on the ability to perform kernel virtul address to PFN
757 + * translations and therefore on 'init_mm'. Unfortunately, the latter is no
758 + * longer exported in recent Linux/x86 2.6 kernels. The export was removed at
759 + * roughtly the same time as the set_pages_{uc,wb}() change_page_attr()
760 + * replacement interfaces were introduced; hopefully, it will be sufficient to
761 + * check for their presence.
762 + */
763  int nv_verify_page_mappings(
764      nv_pte_t *page_ptr,
765      unsigned int cachetype
768 -    struct mm_struct *mm;
769 +#if defined(NV_CHANGE_PAGE_ATTR_PRESENT) || \
770 +    (defined(NV_SET_PAGES_UC_PRESENT) && !defined(NVCPU_X86))
771 +    unsigned long retval = -1;
772 +#if defined(NVCPU_X86) || defined(NVCPU_X86_64)
773      pgd_t *pgd = NULL;
774      pmd_t *pmd = NULL;
775      pte_t *pte = NULL;
776 -    unsigned long retval = -1;
777      unsigned int flags, expected;
778      unsigned long address;
779      static int count = 0;
781 -#if defined(NV_CHANGE_PAGE_ATTR_PRESENT)
782 -    if (!nv_use_cpa)
783 +    if (!nv_update_memory_types)
784          return 0;
785 -#endif
787      address = (unsigned long)__va(page_ptr->phys_addr);
788 -    mm = &init_mm; // always a kernel page
790 -    pgd = NV_PGD_OFFSET(address, 1, mm);
791 +    pgd = NV_PGD_OFFSET(address, 1, NULL);
792      if (!NV_PGD_PRESENT(pgd))
793      {
794          nv_printf(NV_DBG_ERRORS, "NVRM: pgd not present for addr 0x%lx\n", address);
795 @@ -1204,7 +1202,11 @@
796      }
798  failed:
799 +#endif /* defined(NVCPU_X86) || defined(NVCPU_X86_64) */
800      return retval;
801 +#else
802 +    return 0;
803 +#endif
806  #if defined(NV_BUILD_NV_PAT_SUPPORT) && defined(CONFIG_HOTPLUG_CPU)
807 @@ -1250,7 +1252,8 @@
808  static int __init nvidia_init_module(void)
810      int rc;
811 -    U032 i, count;
812 +    U032 i, count, data;
813 +    nv_state_t *nv = NV_STATE_PTR(&nv_ctl_device);
815  #if defined(VM_CHECKER)
816      nv_init_lock(vm_lock);
817 @@ -1266,11 +1269,18 @@
818          return -ENODEV;
819      }
821 +    if (!rm_init_rm())
822 +    {
823 +        nv_printf(NV_DBG_ERRORS, "NVRM: rm_init_rm() failed!\n");
824 +        return -EIO;
825 +    }
827      memset(nv_linux_devices, 0, sizeof(nv_linux_devices));
829      if (pci_register_driver(&nv_pci_driver) < 0)
830      {
831          pci_unregister_driver(&nv_pci_driver); // XXX ???
832 +        rm_shutdown_rm();
833          nv_printf(NV_DBG_ERRORS, "NVRM: No NVIDIA graphics adapter found!\n");
834          return -ENODEV;
835      }
836 @@ -1293,6 +1303,7 @@
837      if (num_probed_nv_devices == 0)
838      {
839          pci_unregister_driver(&nv_pci_driver);
840 +        rm_shutdown_rm();
841          nv_printf(NV_DBG_ERRORS, "NVRM: No NVIDIA graphics adapter probed!\n");
842          return -ENODEV;
843      }
844 @@ -1307,6 +1318,7 @@
845      if (num_nv_devices == 0)
846      {
847          pci_unregister_driver(&nv_pci_driver);
848 +        rm_shutdown_rm();
849          nv_printf(NV_DBG_ERRORS,
850              "NVRM: None of the NVIDIA graphics adapters were initialized!\n");
851          return -ENODEV;
852 @@ -1317,8 +1329,9 @@
853      rc = register_chrdev(nv_major, "nvidia", &nv_fops);
854      if (rc < 0)
855      {
856 -        nv_printf(NV_DBG_ERRORS, "NVRM: register chrdev failed\n");
857          pci_unregister_driver(&nv_pci_driver);
858 +        rm_shutdown_rm();
859 +        nv_printf(NV_DBG_ERRORS, "NVRM: register_chrdev() failed!\n");
860          return rc;
861      }
863 @@ -1367,14 +1380,6 @@
864      }
865  #endif
867 -    // Init the resource manager
868 -    if (!rm_init_rm())
869 -    {
870 -        nv_printf(NV_DBG_ERRORS, "NVRM: rm_init_rm() failed\n");
871 -        rc = -EIO;
872 -        goto failed;
873 -    }
875  #if defined(NV_SG_MAP_BUFFERS)
876      rm_read_registry_dword(NV_STATE_PTR(&nv_ctl_device), "NVreg", "RemapLimit",  &nv_remap_limit);
878 @@ -1407,48 +1412,41 @@
879      /* create /proc/driver/nvidia */
880      nvos_proc_create();
882 -#if defined(NV_CHANGE_PAGE_ATTR_PRESENT)
883 +    /*
884 +     * Give users an opportunity to disable the driver's use of
885 +     * the change_page_attr() and set_pages_{uc,wb}() kernel
886 +     * interfaces.
887 +     */
888 +    rc = rm_read_registry_dword(nv, "NVreg", "UpdateMemoryTypes", &data);
889 +    if ((rc == 0) && ((int)data != ~0))
890      {
891 -        int data;
893 -        // allow the user to override us with a registry key
894 -        rc = rm_read_registry_dword(NV_STATE_PTR(&nv_ctl_device), "NVreg", "UseCPA",  &data);
895 -        if ((rc == 0) && (data != -1))
896 -        {
897 -            nv_use_cpa = data;
898 -        }
899 +        nv_update_memory_types = data;
900 +    }
901  #if defined(NV_CHANGE_PAGE_ATTR_BUG_PRESENT)
902 -        else
903 +    /*
904 +     * Unless we explicitely detect that the change_page_attr()
905 +     * inteface is fixed, disable usage of the interface on
906 +     * this kernel. Notify the user of this problem using the
907 +     * driver's /proc warnings interface (read by the installer
908 +     * and the bug report script).
909 +     */
910 +    else
911 +    {
912 +        rc = nv_verify_cpa_interface();
913 +        if (rc < 0)
914          {
915 -            /*
916 -             * Unless we explicitely detect that the change_page_attr()
917 -             * inteface is fixed, disable usage of the interface on
918 -             * this kernel. Notify the user of this problem using the
919 -             * driver's /proc warnings interface (read by the installer
920 -             * and the bug report script).
921 -             */
922 -            rc = nv_verify_cpa_interface();
923 -            if (rc < 0)
924 -            {
925 -                nv_prints(NV_DBG_ERRORS, __cpgattr_warning);
926 -                nvos_proc_add_warning_file("change_page_attr", __cpgattr_warning);
927 -                nv_use_cpa = 0;
928 -            }
929 -            else if (rc != 0)
930 -            {
931 -                nv_prints(NV_DBG_ERRORS, __cpgattr_warning_2);
932 -                nvos_proc_add_warning_file("change_page_attr", __cpgattr_warning_2);
933 -                nv_use_cpa = 0;
934 -            }
935 +            nv_prints(NV_DBG_ERRORS, __cpgattr_warning);
936 +            nvos_proc_add_warning_file("change_page_attr", __cpgattr_warning);
937 +            nv_update_memory_types = 0;
938 +        }
939 +        else if (rc != 0)
940 +        {
941 +            nv_prints(NV_DBG_ERRORS, __cpgattr_warning_2);
942 +            nvos_proc_add_warning_file("change_page_attr", __cpgattr_warning_2);
943 +            nv_update_memory_types = 0;
944          }
945 -#endif
946      }
947 -#endif
950 -#if defined(DEBUG)
951 -    inter_module_register("nv_linux_devices", THIS_MODULE, nv_linux_devices);
952 -#endif
953 +#endif /* defined(NV_CHANGE_PAGE_ATTR_BUG_PRESENT) */
955  #if defined(NVCPU_X86_64) && defined(CONFIG_IA32_EMULATION) && !defined(HAVE_COMPAT_IOCTL)
956      /* Register ioctl conversions for 32 bit clients */
957 @@ -1501,6 +1499,8 @@
958      }
960      pci_unregister_driver(&nv_pci_driver);
961 +    rm_shutdown_rm();
963      return rc;
966 @@ -1532,10 +1532,6 @@
967      /* remove /proc/driver/nvidia */
968      nvos_proc_remove();
970 -#if defined(DEBUG)
971 -    inter_module_unregister("nv_linux_devices");
972 -#endif
974  #if defined(NV_PM_SUPPORT_OLD_STYLE_APM)
975      for (i = 0; i < num_nv_devices; i++)
976      {
977 @@ -2112,6 +2108,8 @@
978          if (rm_validate_pfn_range(file, NV_VMA_PGOFF(vma),
979                  NV_VMA_SIZE(vma)) == RM_OK)
980          {
981 +            if (vma->vm_flags & VM_WRITE)
982 +                return -EACCES;
983              vma->vm_flags |= (VM_IO | VM_LOCKED);
984  #if defined(NV_VM_INSERT_PAGE_PRESENT)
985              if (NV_VM_INSERT_PAGE(vma, vma->vm_start, pfn_to_page(NV_VMA_PGOFF(vma))))
986 @@ -2240,6 +2238,8 @@
987              if (rm_validate_pfn_range(file, NV_VMA_PGOFF(vma),
988                      NV_VMA_SIZE(vma)) == RM_OK)
989              {
990 +                if (vma->vm_flags & VM_WRITE)
991 +                    return -EACCES;
992                  vma->vm_flags |= (VM_IO | VM_LOCKED);
993  #if defined(NV_VM_INSERT_PAGE_PRESENT)
994                  if (NV_VM_INSERT_PAGE(vma, vma->vm_start, pfn_to_page(NV_VMA_PGOFF(vma))))
995 @@ -3266,8 +3266,21 @@
996      pte_t *pte = NULL;
997      unsigned long retval;
999 -    mm = (kern) ? &init_mm : current->mm;
1000 -    if (!kern) down_read(&current->mm->mmap_sem);
1001 +    if (!kern)
1002 +    {
1003 +        mm = current->mm;
1004 +        down_read(&mm->mmap_sem);
1005 +    }
1006 +    else
1007 +    {
1008 +#if defined(NV_SET_PAGES_UC_PRESENT) && defined(NVCPU_X86)
1009 +        /* nv_printf(NV_DBG_ERRORS,
1010 +            "NVRM: can't translate KVA in nv_get_phys_address()!\n"); */
1011 +        return 0;
1012 +#else
1013 +        mm = NULL;
1014 +#endif
1015 +    }
1017      pgd = NV_PGD_OFFSET(address, kern, mm);
1018      if (!NV_PGD_PRESENT(pgd))
1019 @@ -3288,11 +3301,13 @@
1020      retval &= ~_PAGE_NX;
1021  #endif
1023 -    if (!kern) up_read(&current->mm->mmap_sem);
1024 +    if (!kern)
1025 +        up_read(&mm->mmap_sem);
1026      return retval;
1028  failed:
1029 -    if (!kern) up_read(&current->mm->mmap_sem);
1030 +    if (!kern)
1031 +        up_read(&mm->mmap_sem);
1032      return 0;
1035 @@ -3300,12 +3315,19 @@
1036      unsigned long address
1039 -    // make sure this address is a kernel pointer
1040 +#if defined(NV_SET_PAGES_UC_PRESENT) && defined(NVCPU_X86)
1041 +    nv_linux_state_t *nvl;
1042 +    nv_alloc_t *at;
1043 +    unsigned long virt_addr;
1044 +    U032 i, j;
1045 +#endif
1047 +    /* make sure this address is a kernel virtual address */
1048  #if defined(DEBUG) && !defined(CONFIG_X86_4G)
1049      if (address < PAGE_OFFSET)
1050      {
1051          nv_printf(NV_DBG_WARNINGS,
1052 -            "NVRM: user address passed to get_kern_phys_address: 0x%lx\n",
1053 +            "NVRM: user address passed to get_kern_phys_address: 0x%llx!\n",
1054              address);
1055          return 0;
1056      }
1057 @@ -3315,6 +3337,30 @@
1058      if ((address > PAGE_OFFSET) && (address < VMALLOC_START))
1059          return __pa(address);
1061 +#if defined(NV_SET_PAGES_UC_PRESENT) && defined(NVCPU_X86)
1062 +    for (i = 0; i < num_nv_devices; i++)
1063 +    {
1064 +        nvl = &nv_linux_devices[i];
1066 +        for (at = nvl->alloc_queue; (at != NULL); at = at->next)
1067 +        {
1068 +            if (!NV_ALLOC_MAPPING_VMAP(at->flags))
1069 +                continue;
1071 +            for (j = 0; j < at->num_pages; j++)
1072 +            {
1073 +                virt_addr = at->page_table[j]->virt_addr;
1074 +                if ((address >= virt_addr) &&
1075 +                        (address < (virt_addr + PAGE_SIZE)))
1076 +                {
1077 +                    return (at->page_table[j]->phys_addr +
1078 +                            (address & ~PAGE_MASK));
1079 +                }
1080 +            }
1081 +        }
1082 +    }
1083 +#endif
1085      return _get_phys_address(address, 1);
1088 @@ -3322,12 +3368,12 @@
1089      unsigned long address
1092 -    // make sure this address is not a kernel pointer
1093 +    /* make sure this address is not a kernel virtual address */
1094  #if defined(DEBUG) && !defined(CONFIG_X86_4G)
1095      if (address >= PAGE_OFFSET)
1096      {
1097          nv_printf(NV_DBG_WARNINGS,
1098 -            "NVRM: kernel address passed to get_user_phys_address: 0x%lx\n",
1099 +            "NVRM: kernel address passed to get_user_phys_address: 0x%llx!\n",
1100              address);
1101          return 0;
1102      }
1103 @@ -3396,8 +3442,6 @@
1104              if (nv_vm_malloc_pages(nv, at))
1105                  goto failed;
1107 -            at->class = class;
1109              // set our 'key' to the page_table. rm_alloc_agp_pages will call
1110              // nv_translate_address below, which will look up pages using
1111              // the value of *pAddress as a key, then index into the page_table
1112 @@ -3952,7 +3996,8 @@
1114      if (num_nv_devices == NV_MAX_DEVICES)
1115      {
1116 -        nv_printf(NV_DBG_ERRORS, "NVRM: maximum device number (%d) reached!\n", num_nv_devices);
1117 +        nv_printf(NV_DBG_ERRORS, "NVRM: maximum device number (%d) exceeded!\n",
1118 +                  (NV_MAX_DEVICES - 1));
1119          return -1;
1120      }
1122 @@ -4085,13 +4130,10 @@
1123      return -1;
1126 -int NV_API_CALL nv_no_incoherent_mappings
1128 -    void
1130 +int NV_API_CALL nv_no_incoherent_mappings(void)
1132 -#if defined(NV_CHANGE_PAGE_ATTR_PRESENT)
1133 -    return 1;
1134 +#if defined(NV_CHANGE_PAGE_ATTR_PRESENT) || defined(NV_SET_PAGES_UC_PRESENT)
1135 +    return (nv_update_memory_types);
1136  #else
1137      return 0;
1138  #endif
1139 diff -ru usr/src/nv/nv.h usr/src/nv.2305230/nv.h
1140 --- usr/src/nv/nv.h     2008-01-21 11:48:11.000000000 -0800
1141 +++ usr/src/nv.2305230/nv.h     2008-03-18 12:55:56.919649651 -0700
1142 @@ -335,15 +332,39 @@
1144  #define NV_DEVICE_NAME_LENGTH 40
1146 +#define NV_MAX_ISR_DELAY_US           20000
1147 +#define NV_MAX_ISR_DELAY_MS           (NV_MAX_ISR_DELAY_US / 1000)
1149 +#define NV_TIMERCMP(a, b, CMP)                                              \
1150 +    (((a)->tv_sec == (b)->tv_sec) ?                                         \
1151 +        ((a)->tv_usec CMP (b)->tv_usec) : ((a)->tv_sec CMP (b)->tv_sec))
1153 +#define NV_TIMERADD(a, b, result)                                           \
1154 +    {                                                                       \
1155 +        (result)->tv_sec = (a)->tv_sec + (b)->tv_sec;                       \
1156 +        (result)->tv_usec = (a)->tv_usec + (b)->tv_usec;                    \
1157 +        if ((result)->tv_usec >= 1000000)                                   \
1158 +        {                                                                   \
1159 +            ++(result)->tv_sec;                                             \
1160 +            (result)->tv_usec -= 1000000;                                   \
1161 +        }                                                                   \
1162 +    }
1164 +#define NV_TIMERSUB(a, b, result)                                           \
1165 +    {                                                                       \
1166 +        (result)->tv_sec = (a)->tv_sec - (b)->tv_sec;                       \
1167 +        (result)->tv_usec = (a)->tv_usec - (b)->tv_usec;                    \
1168 +        if ((result)->tv_usec < 0)                                          \
1169 +        {                                                                   \
1170 +          --(result)->tv_sec;                                               \
1171 +          (result)->tv_usec += 1000000;                                     \
1172 +        }                                                                   \
1173 +    }
1175  /*
1176   * driver internal interfaces
1177   */
1179 -/* need a fake device number for control device; just to flag it for msgs */
1180 -#define NV_CONTROL_DEVICE_NUMBER     100
1183  #ifndef NVWATCH
1185  /*
1186 diff -ru usr/src/nv/os-interface.c usr/src/nv.2305230/os-interface.c
1187 --- usr/src/nv/os-interface.c   2008-01-21 11:48:11.000000000 -0800
1188 +++ usr/src/nv.2305230/os-interface.c   2008-03-18 12:56:04.288069559 -0700
1189 @@ -25,7 +25,6 @@
1190  #include "os-interface.h"
1191  #include "nv-linux.h"
1194  static volatile int os_block_on_smp_barrier;
1196  #ifdef CONFIG_SMP
1197 @@ -63,7 +62,7 @@
1198  //
1199  typedef struct os_sema_s
1201 -    struct semaphore wait;
1202 +    struct completion  completion;
1203      spinlock_t       lock;
1204      S032             count;
1205  } os_sema_t;
1206 @@ -86,7 +85,7 @@
1207          return rmStatus;
1209      os_sema = (os_sema_t *)*ppSema;
1210 -    sema_init(&os_sema->wait, 0);
1211 +    init_completion(&os_sema->completion);
1212      spin_lock_init(&os_sema->lock);
1213      os_sema->count = 1;
1215 @@ -131,7 +130,7 @@
1216      {
1217          os_sema->count--;
1218          spin_unlock_irqrestore(&os_sema->lock, old_irq);
1219 -        down(&os_sema->wait);
1220 +        wait_for_completion(&os_sema->completion);
1221      }
1222      else
1223      {
1224 @@ -208,7 +207,7 @@
1225      spin_unlock_irqrestore(&os_sema->lock, old_irq);
1227      if (doWakeup)
1228 -        up(&os_sema->wait);
1229 +        complete(&os_sema->completion);
1231      return RM_OK;
1233 @@ -448,8 +447,6 @@
1234  //
1235  //---------------------------------------------------------------------------
1237 -#define NV_MAX_ISR_UDELAY           20000
1238 -#define NV_MAX_ISR_MDELAY           (NV_MAX_ISR_UDELAY / 1000)
1239  #define NV_MSECS_PER_JIFFIE         (1000 / HZ)
1240  #define NV_MSECS_TO_JIFFIES(msec)   ((msec) * HZ / 1000)
1241  #define NV_USECS_PER_JIFFIE         (1000000 / HZ)
1242 @@ -474,7 +471,7 @@
1243      do_gettimeofday(&tm1);
1244  #endif
1246 -    if (in_irq() && MicroSeconds > NV_MAX_ISR_UDELAY)
1247 +    if (in_irq() && (MicroSeconds > NV_MAX_ISR_DELAY_US))
1248          return RM_ERROR;
1249      
1250      mdelay_safe_msec = MicroSeconds / 1000;
1251 @@ -494,36 +491,6 @@
1252      return RM_OK;
1255 -#ifndef timercmp
1256 -# define timercmp(a, b, CMP)                                                  \
1257 -  (((a)->tv_sec == (b)->tv_sec) ?                                             \
1258 -   ((a)->tv_usec CMP (b)->tv_usec) :                                          \
1259 -   ((a)->tv_sec CMP (b)->tv_sec))
1260 -#endif
1261 -#ifndef timeradd
1262 -# define timeradd(a, b, result)                                               \
1263 -  do {                                                                        \
1264 -    (result)->tv_sec = (a)->tv_sec + (b)->tv_sec;                             \
1265 -    (result)->tv_usec = (a)->tv_usec + (b)->tv_usec;                          \
1266 -    if ((result)->tv_usec >= 1000000)                                         \
1267 -      {                                                                       \
1268 -        ++(result)->tv_sec;                                                   \
1269 -        (result)->tv_usec -= 1000000;                                         \
1270 -      }                                                                       \
1271 -  } while (0)
1272 -#endif
1273 -#ifndef timersub
1274 -# define timersub(a, b, result)                                               \
1275 -  do {                                                                        \
1276 -    (result)->tv_sec = (a)->tv_sec - (b)->tv_sec;                             \
1277 -    (result)->tv_usec = (a)->tv_usec - (b)->tv_usec;                          \
1278 -    if ((result)->tv_usec < 0) {                                              \
1279 -      --(result)->tv_sec;                                                     \
1280 -      (result)->tv_usec += 1000000;                                           \
1281 -    }                                                                         \
1282 -  } while (0)
1283 -#endif
1285  /* 
1286   * On Linux, a jiffie represents the time passed in between two timer
1287   * interrupts. The number of jiffies per second (HZ) varies across the
1288 @@ -549,7 +516,7 @@
1289      tm_start = tm_aux;
1290  #endif
1292 -    if (in_irq() && MilliSeconds > NV_MAX_ISR_MDELAY)
1293 +    if (in_irq() && (MilliSeconds > NV_MAX_ISR_DELAY_MS))
1294          return RM_ERROR;
1296      if (!NV_MAY_SLEEP()) 
1297 @@ -561,7 +528,7 @@
1298      MicroSeconds = MilliSeconds * 1000;
1299      tm_end.tv_usec = MicroSeconds;
1300      tm_end.tv_sec = 0;
1301 -    timeradd(&tm_aux, &tm_end, &tm_end);
1302 +    NV_TIMERADD(&tm_aux, &tm_end, &tm_end);
1304      /* do we have a full jiffie to wait? */
1305      jiffies = NV_USECS_TO_JIFFIES(MicroSeconds);
1306 @@ -590,9 +557,9 @@
1307              schedule_timeout(jiffies);
1308              /* catch the remainder, if any */
1309              do_gettimeofday(&tm_aux);
1310 -            if (timercmp(&tm_aux, &tm_end, <))
1311 +            if (NV_TIMERCMP(&tm_aux, &tm_end, <))
1312              {
1313 -                timersub(&tm_end, &tm_aux, &tm_aux);    //  tm_aux = tm_end - tm_aux
1314 +                NV_TIMERSUB(&tm_end, &tm_aux, &tm_aux); // tm_aux = tm_end - tm_aux
1315                  MicroSeconds = tm_aux.tv_usec + tm_aux.tv_sec * 1000000;
1316              } else
1317                  MicroSeconds = 0;
1318 @@ -1109,6 +1076,18 @@
1320      void *vaddr;
1322 +    if (start == 0)
1323 +    {
1324 +        if (mode != NV_MEMORY_CACHED)
1325 +        {
1326 +            nv_printf(NV_DBG_ERRORS,
1327 +                "NVRM: os_map_kernel_space: won't map address 0x%0llx UC!\n", start);
1328 +            return NULL;
1329 +        }
1330 +        else
1331 +            return (void *)PAGE_OFFSET;
1332 +    }
1334      if (!NV_MAY_SLEEP())
1335      {
1336          nv_printf(NV_DBG_ERRORS,
1337 @@ -1131,6 +1110,9 @@
1338      U032 size_bytes
1341 +    if (addr == (void *)PAGE_OFFSET)
1342 +        return;
1344      NV_IOUNMAP(addr, size_bytes);
1347 @@ -1176,7 +1158,11 @@
1348  #if defined(CONFIG_X86_REMOTE_DEBUG)
1349          __asm__ __volatile__ ("int $3");
1350  #elif defined(CONFIG_KGDB)
1351 +#if defined(NV_OLD_MM_KGDB_BREAKPOINT_PRESENT)
1352 +        BREAKPOINT;
1353 +#else
1354          BREAKPOINT();
1355 +#endif
1356  #elif defined(CONFIG_KDB)
1357      KDB_ENTER();
1358  #else
1359 diff -ru usr/src/nv/os-registry.c usr/src/nv.2305230/os-registry.c
1360 --- usr/src/nv/os-registry.c    2008-01-21 11:48:11.000000000 -0800
1361 +++ usr/src/nv.2305230/os-registry.c    2008-03-18 12:56:07.492252151 -0700
1362 @@ -48,24 +48,6 @@
1363   *   This could be changed to work on a per-device basis.
1364   */
1367 - * The 2nd argument to MODULE_PARM is used to verify parameters passed
1368 - * to the module at load time. It should be a string in the following 
1369 - * format:
1370 - *
1371 - *      [min[-max]]{b,h,i,l,s}
1372 - *
1373 - * The MIN and MAX specifiers delimit the length of the array. If MAX
1374 - * is omitted, it defaults to MIN; if both are omitted, the default is
1375 - * 1. The final character is a type specifier.
1376 - *
1377 - *  b   byte
1378 - *  h   short
1379 - *  i   int
1380 - *  l   long
1381 - *  s   string
1382 - */
1384  /* 
1385   * Option: VideoMemoryTypeOverride
1386   * 
1387 @@ -360,9 +342,6 @@
1388  static int NVreg_DevicesConnected = 0;
1389  NV_MODULE_PARAMETER(NVreg_DevicesConnected);
1391 -static int NVreg_VideoEnhancement = 0;
1392 -NV_MODULE_PARAMETER(NVreg_VideoEnhancement);
1394  static int NVreg_RmLogonRC = 1;
1395  NV_MODULE_PARAMETER(NVreg_RmLogonRC);
1397 @@ -402,34 +381,36 @@
1398  NV_MODULE_PARAMETER(NVreg_RemapLimit);
1400  /*
1401 - * Option: UseCPA
1402 + * Option: UpdateMemoryTypes
1403   *
1404   * Description:
1405   *
1406 - * Many kernels have a broken implementation of change_page_attr that leads
1407 - * to cache aliasing problems. x86_64 kernels between 2.6.0 and 2.6.10 will
1408 - * force a kernel BUG_ON() when this condition is encountered. For this
1409 - * reason, the NVIDIA driver is very careful about not using the CPA kernel
1410 - * interface on these kernels.
1411 + * Many kernels have broken implementations of the change_page_attr()
1412 + * kernel interface that may cause cache aliasing problems. Linux/x86-64
1413 + * kernels between 2.6.0 and 2.6.10 may prompt kernel BUG()s due to
1414 + * improper accounting in the interface's large page management code, for
1415 + * example. For this reason, the NVIDIA Linux driver is very careful about
1416 + * not using the change_page_attr() kernel interface on these kernels.
1417 + *
1418 + * Due to the serious nature of the problems that can arise from bugs in
1419 + * the change_page_attr(), set_pages_{uc,wb}() and other kernel interfaces
1420 + * used to modify memory types, the NVIDIA driver implements a manual
1421 + * registry key override to allow forcibly enabling or disabling use of
1422 + * these APIs.
1423   *
1424 - * Some distributions have backported this fix to kernel versions that fall
1425 - * within this version range. The NVIDIA driver attempts to automatically
1426 - * detect these fixes and reenable usage of the change_page_attr interface.
1427 + * Possible values:
1428   *
1429 - * Due to the serious nature of the problems that can arise from this, the
1430 - * NVIDIA driver implements a manual registry key to force usage of this API
1431 - * to be enabled or disabled. This registry key can be used to force usage
1432 - * of the API on a known fixed kernel if the NVIDIA driver fails to detect
1433 - * the kernel as fixed. This registry key can also be used to disable usage
1434 - * of the API on a bad kernel that is misdetected as a fixed kernel.
1435 + * ~0 = use the NVIDIA driver's default logic (default)
1436 + *  0 = enable use of change_page_attr(), etc.
1437 + *  1 = disable use of change_page_attr(), etc.
1438   *
1439 - * The default value is '-1' (use NVIDIA driver default logic)
1440 - * A value of '0' will forcibly disable change_page_attr calls.
1441 - * A value of '1' will forcibly enable change_page_attr calls.
1442 + * By default, the NVIDIA driver will attempt to auto-detect if it can
1443 + * safely use the change_page_attr() and other kernel interfaces to modify
1444 + * the memory types of kernel mappings.
1445   */
1447 -static int NVreg_UseCPA = -1;
1448 -NV_MODULE_PARAMETER(NVreg_UseCPA);
1449 +static int NVreg_UpdateMemoryTypes = ~0;
1450 +NV_MODULE_PARAMETER(NVreg_UpdateMemoryTypes);
1452  // 1 - Force sourcing vbios from ROM
1453  // 0 - business as usual
1454 @@ -477,15 +458,14 @@
1455      { "NVreg",  "ResmanDebugLevel",         &NVreg_ResmanDebugLevel,         1 },
1456      { "NVreg",  "FlatPanelMode",            &NVreg_FlatPanelMode,            1 },
1457      { "NVreg",  "DevicesConnected",         &NVreg_DevicesConnected,         1 },
1458 -    { "NVreg",  "VideoEnhancement",         &NVreg_VideoEnhancement,         1 },
1459      { "NVreg",  "RmLogonRC",                &NVreg_RmLogonRC,                1 },
1460 +    { "NVreg",  "VbiosFromROM",             &NVreg_VbiosFromROM,             1 },
1461      { "NVreg",  "ModifyDeviceFiles",        &NVreg_ModifyDeviceFiles,        1 },
1462      { "NVreg",  "DeviceFileUID",            &NVreg_DeviceFileUID,            1 },
1463      { "NVreg",  "DeviceFileGID",            &NVreg_DeviceFileGID,            1 },
1464      { "NVreg",  "DeviceFileMode",           &NVreg_DeviceFileMode,           1 },
1465 -    { "NVreg",  "VbiosFromROM",             &NVreg_VbiosFromROM,             1 },
1466      { "NVreg",  "RemapLimit",               &NVreg_RemapLimit,               1 },
1467 -    { "NVreg",  "UseCPA",                   &NVreg_UseCPA,                   1 },
1468 +    { "NVreg",  "UpdateMemoryTypes",        &NVreg_UpdateMemoryTypes,        1 },
1469      { "NVreg",  "RMEdgeIntrCheck",          &NVreg_RMEdgeIntrCheck,          1 },
1470      {  NULL,     NULL,                      NULL,                            0 }
1471  };