]>
Commit | Line | Data |
---|---|---|
91e02d0c | 1 | diff -ru usr/src/nv/Makefile.kbuild usr/src/nv.2286310/Makefile.kbuild |
2 | --- usr/src/nv/Makefile.kbuild 2008-03-16 14:13:10.000000000 -0700 | |
3 | +++ usr/src/nv.2286310/Makefile.kbuild 2008-03-16 14:37:47.204131496 -0700 | |
4 | @@ -177,6 +177,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.2286310/conftest.sh | |
13 | --- usr/src/nv/conftest.sh 2008-03-16 14:13:10.000000000 -0700 | |
14 | +++ usr/src/nv.2286310/conftest.sh 2008-03-16 14:37:47.204131496 -0700 | |
15 | @@ -100,6 +100,32 @@ | |
16 | fi | |
17 | ;; | |
18 | ||
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 | |
28 | + | |
29 | + $CC $CFLAGS -c conftest$$.c > /dev/null 2>&1 | |
30 | + rm -f conftest$$.c | |
31 | + | |
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 | + ;; | |
44 | + | |
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 | @@ -524,6 +552,8 @@ | |
59 | return | |
60 | fi | |
61 | ||
62 | + rm -f conftest$$.o | |
63 | + | |
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.2286310/nv-linux.h | |
68 | --- usr/src/nv/nv-linux.h 2008-03-16 14:13:10.000000000 -0700 | |
69 | +++ usr/src/nv.2286310/nv-linux.h 2008-03-16 14:37:47.204131496 -0700 | |
70 | @@ -871,9 +871,10 @@ | |
71 | ||
72 | #define NV_PGD_OFFSET(address, kernel, mm) \ | |
73 | ({ \ | |
74 | + struct mm_struct *__mm = (mm); \ | |
75 | pgd_t *__pgd; \ | |
76 | if (!kernel) \ | |
77 | - __pgd = pgd_offset(mm, address); \ | |
78 | + __pgd = pgd_offset(__mm, address); \ | |
79 | else \ | |
80 | __pgd = pgd_offset_k(address); \ | |
81 | __pgd; \ | |
82 | @@ -1208,21 +1209,24 @@ | |
83 | nv_check_pci_config_space(nv, cb); \ | |
84 | } | |
85 | ||
86 | +extern int nv_update_memory_types; | |
87 | + | |
88 | /* | |
89 | - * a BUG() is triggered on early 2.6 x86_64 kernels. the underlying | |
90 | - * problem actually exists on many architectures and kernels, but | |
91 | - * these are the only kernels that check the condition and trigger | |
92 | - * a BUG(). note that this is a problem of the core kernel, not an | |
93 | - * nvidia bug (and can still be triggered by agpgart). let's avoid | |
94 | - * change_page_attr on those kernels. | |
95 | + * Using change_page_attr() on early Linux/x86-64 2.6 kernels may | |
96 | + * result in a BUG() being triggered. The underlying problem | |
97 | + * actually exists on multiple architectures and kernels, but only | |
98 | + * the above check for the condition and trigger a BUG(). | |
99 | + * | |
100 | + * Note that this is a due to a bug in the Linux kernel, not an | |
101 | + * NVIDIA driver bug (it can also be triggered by AGPGART). | |
102 | + * | |
103 | + * We therefore need to determine at runtime if change_page_attr() | |
104 | + * can be used safely on these kernels. | |
105 | */ | |
106 | -#if defined(NV_CHANGE_PAGE_ATTR_PRESENT) | |
107 | -extern int nv_use_cpa; | |
108 | - | |
109 | -#if defined(NVCPU_X86_64) && !defined(KERNEL_2_4) && \ | |
110 | - (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 11)) | |
111 | -#define NV_CHANGE_PAGE_ATTR_BUG_PRESENT 1 | |
112 | -#endif | |
113 | +#if defined(NV_CHANGE_PAGE_ATTR_PRESENT) && defined(NVCPU_X86_64) && \ | |
114 | + !defined(KERNEL_2_4) && \ | |
115 | + (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 11)) | |
116 | +#define NV_CHANGE_PAGE_ATTR_BUG_PRESENT | |
117 | #endif | |
118 | ||
119 | #if defined(NVCPU_X86) || defined(NVCPU_X86_64) | |
120 | @@ -1234,7 +1238,7 @@ | |
121 | * | |
122 | * We need to be careful to mask out _PAGE_NX when the host system | |
123 | * doesn't support this feature or when it's disabled: the kernel | |
124 | - * may not do this in its implementation of the change_page_attr() | |
125 | + * may not do this in its implementation of the change_page_attr() | |
126 | * interface. | |
127 | */ | |
128 | #ifndef X86_FEATURE_NX | |
129 | diff -ru usr/src/nv/nv-reg.h usr/src/nv.2286310/nv-reg.h | |
130 | --- usr/src/nv/nv-reg.h 2008-03-16 14:13:10.000000000 -0700 | |
131 | +++ usr/src/nv.2286310/nv-reg.h 2008-03-16 14:37:47.204131496 -0700 | |
132 | @@ -391,34 +391,36 @@ | |
133 | #define NV_REG_REMAP_LIMIT NV_REG_STRING(__NV_REMAP_LIMIT) | |
134 | ||
135 | /* | |
136 | - * Option: UseCPA | |
137 | + * Option: UpdateMemoryTypes | |
138 | * | |
139 | * Description: | |
140 | * | |
141 | - * Many kernels have a broken implementation of change_page_attr that leads | |
142 | - * to cache aliasing problems. x86_64 kernels between 2.6.0 and 2.6.10 will | |
143 | - * force a kernel BUG_ON() when this condition is encountered. For this | |
144 | - * reason, the NVIDIA driver is very careful about not using the CPA kernel | |
145 | - * interface on these kernels. | |
146 | - * | |
147 | - * Some distributions have backported this fix to kernel versions that fall | |
148 | - * within this version range. The NVIDIA driver attempts to automatically | |
149 | - * detect these fixes and reenable usage of the change_page_attr interface. | |
150 | - * | |
151 | - * Due to the serious nature of the problems that can arise from this, the | |
152 | - * NVIDIA driver implements a manual registry key to force usage of this API | |
153 | - * to be enabled or disabled. This registry key can be used to force usage | |
154 | - * of the API on a known fixed kernel if the NVIDIA driver fails to detect | |
155 | - * the kernel as fixed. This registry key can also be used to disable usage | |
156 | - * of the API on a bad kernel that is misdetected as a fixed kernel. | |
157 | - * | |
158 | - * The default value is '-1' (use NVIDIA driver default logic) | |
159 | - * A value of '0' will forcibly disable change_page_attr calls. | |
160 | - * A value of '1' will forcibly enable change_page_attr calls. | |
161 | + * Many kernels have broken implementations of the change_page_attr() | |
162 | + * kernel interface that may cause cache aliasing problems. Linux/x86-64 | |
163 | + * kernels between 2.6.0 and 2.6.10 may prompt kernel BUG()s due to | |
164 | + * improper accounting in the interface's large page management code, for | |
165 | + * example. For this reason, the NVIDIA Linux driver is very careful about | |
166 | + * not using the change_page_attr() kernel interface on these kernels. | |
167 | + * | |
168 | + * Due to the serious nature of the problems that can arise from bugs in | |
169 | + * the change_page_attr(), set_pages_{uc,wb}() and other kernel interfaces | |
170 | + * used to modify memory types, the NVIDIA driver implements a manual | |
171 | + * registry key override to allow forcibly enabling or disabling use of | |
172 | + * these APIs. | |
173 | + * | |
174 | + * Possible values: | |
175 | + * | |
176 | + * ~0 = use the NVIDIA driver's default logic (default) | |
177 | + * 0 = enable use of change_page_attr(), etc. | |
178 | + * 1 = disable use of change_page_attr(), etc. | |
179 | + * | |
180 | + * By default, the NVIDIA driver will attempt to auto-detect if it can | |
181 | + * safely use the change_page_attr() and other kernel interfaces to modify | |
182 | + * the memory types of kernel mappings. | |
183 | */ | |
184 | ||
185 | -#define __NV_USE_CPA UseCPA | |
186 | -#define NV_REG_USE_CPA NV_REG_STRING(__NV_USE_CPA) | |
187 | +#define __NV_UPDATE_MEMORY_TYPES UpdateMemoryTypes | |
188 | +#define NV_REG_UPDATE_MEMORY_TYPES NV_REG_STRING(__NV_UPDATE_MEMORY_TYPES) | |
189 | ||
190 | /* | |
191 | * Option: RegistryDwords | |
192 | @@ -490,7 +492,7 @@ | |
193 | NV_DEFINE_REG_ENTRY(__NV_DEVICE_FILE_GID, 0); | |
194 | NV_DEFINE_REG_ENTRY(__NV_DEVICE_FILE_MODE, 0666); | |
195 | NV_DEFINE_REG_ENTRY(__NV_REMAP_LIMIT, 0); | |
196 | -NV_DEFINE_REG_ENTRY(__NV_USE_CPA, -1); | |
197 | +NV_DEFINE_REG_ENTRY(__NV_UPDATE_MEMORY_TYPES, ~0); | |
198 | NV_DEFINE_REG_ENTRY(__NV_USE_VBIOS, 1); | |
199 | NV_DEFINE_REG_ENTRY(__NV_RM_EDGE_INTR_CHECK, 1); | |
200 | ||
201 | @@ -535,7 +537,7 @@ | |
202 | NV_DEFINE_PARAMS_TABLE_ENTRY(__NV_DEVICE_FILE_GID), | |
203 | NV_DEFINE_PARAMS_TABLE_ENTRY(__NV_DEVICE_FILE_MODE), | |
204 | NV_DEFINE_PARAMS_TABLE_ENTRY(__NV_REMAP_LIMIT), | |
205 | - NV_DEFINE_PARAMS_TABLE_ENTRY(__NV_USE_CPA), | |
206 | + NV_DEFINE_PARAMS_TABLE_ENTRY(__NV_UPDATE_MEMORY_TYPES), | |
207 | NV_DEFINE_PARAMS_TABLE_ENTRY(__NV_USE_VBIOS), | |
208 | NV_DEFINE_PARAMS_TABLE_ENTRY(__NV_RM_EDGE_INTR_CHECK), | |
209 | {NULL, NULL, NULL} | |
210 | diff -ru usr/src/nv/nv-vm.c usr/src/nv.2286310/nv-vm.c | |
211 | --- usr/src/nv/nv-vm.c 2008-03-16 14:13:09.000000000 -0700 | |
212 | +++ usr/src/nv.2286310/nv-vm.c 2008-03-16 14:37:47.204131496 -0700 | |
213 | @@ -43,42 +43,40 @@ | |
214 | } | |
215 | #endif | |
216 | ||
217 | -/* | |
218 | - * AMD Athlon processors expose a subtle bug in the Linux | |
219 | - * kernel, that may lead to AGP memory corruption. Recent | |
220 | - * kernel versions had a workaround for this problem, but | |
221 | - * 2.4.20 is the first kernel to address it properly. The | |
222 | - * page_attr API provides the means to solve the problem. | |
223 | - */ | |
224 | - | |
225 | static inline void nv_set_page_attrib_uncached(nv_pte_t *page_ptr) | |
226 | { | |
227 | -#if defined(NV_CHANGE_PAGE_ATTR_PRESENT) | |
228 | - if (nv_use_cpa) | |
229 | + if (nv_update_memory_types) | |
230 | { | |
231 | - struct page *page = virt_to_page(__va(page_ptr->phys_addr)); | |
232 | +#if defined(NV_SET_PAGES_UC_PRESENT) | |
233 | + struct page *page = NV_GET_PAGE_STRUCT(page_ptr->phys_addr); | |
234 | + set_pages_uc(page, 1); | |
235 | +#elif defined(NV_CHANGE_PAGE_ATTR_PRESENT) | |
236 | + struct page *page = NV_GET_PAGE_STRUCT(page_ptr->phys_addr); | |
237 | pgprot_t prot = PAGE_KERNEL_NOCACHE; | |
238 | #if defined(NVCPU_X86) || defined(NVCPU_X86_64) | |
239 | pgprot_val(prot) &= __nv_supported_pte_mask; | |
240 | #endif | |
241 | change_page_attr(page, 1, prot); | |
242 | - } | |
243 | #endif | |
244 | + } | |
245 | } | |
246 | ||
247 | static inline void nv_set_page_attrib_cached(nv_pte_t *page_ptr) | |
248 | { | |
249 | -#if defined(NV_CHANGE_PAGE_ATTR_PRESENT) | |
250 | - if (nv_use_cpa) | |
251 | + if (nv_update_memory_types) | |
252 | { | |
253 | - struct page *page = virt_to_page(__va(page_ptr->phys_addr)); | |
254 | +#if defined(NV_SET_PAGES_UC_PRESENT) | |
255 | + struct page *page = NV_GET_PAGE_STRUCT(page_ptr->phys_addr); | |
256 | + set_pages_wb(page, 1); | |
257 | +#elif defined(NV_CHANGE_PAGE_ATTR_PRESENT) | |
258 | + struct page *page = NV_GET_PAGE_STRUCT(page_ptr->phys_addr); | |
259 | pgprot_t prot = PAGE_KERNEL; | |
260 | #if defined(NVCPU_X86) || defined(NVCPU_X86_64) | |
261 | pgprot_val(prot) &= __nv_supported_pte_mask; | |
262 | #endif | |
263 | change_page_attr(page, 1, prot); | |
264 | +#endif | |
265 | } | |
266 | -#endif /* NV_CHANGE_PAGE_ATTR_PRESENT */ | |
267 | } | |
268 | ||
269 | static inline void nv_lock_page(nv_pte_t *page_ptr) | |
270 | @@ -360,7 +358,8 @@ | |
271 | #if defined(NV_CPA_NEEDS_FLUSHING) | |
272 | nv_execute_on_all_cpus(cache_flush, NULL); | |
273 | #endif | |
274 | -#if defined (NVCPU_X86) || defined (NVCPU_X86_64) | |
275 | +#if (defined(NVCPU_X86) || defined(NVCPU_X86_64)) && \ | |
276 | + defined(NV_CHANGE_PAGE_ATTR_PRESENT) | |
277 | global_flush_tlb(); | |
278 | #endif | |
279 | nv_ext_flush_caches(); // handle other platform flushes if present | |
280 | @@ -662,7 +661,7 @@ | |
281 | ||
282 | address = (unsigned long)virt_addr + i * PAGE_SIZE; | |
283 | ||
284 | - pgd = NV_PGD_OFFSET(address, 1, &init_mm); | |
285 | + pgd = NV_PGD_OFFSET(address, 1, NULL); | |
286 | if (!NV_PGD_PRESENT(pgd)) | |
287 | goto failed; | |
288 | ||
289 | diff -ru usr/src/nv/nv.c usr/src/nv.2286310/nv.c | |
290 | --- usr/src/nv/nv.c 2008-03-16 14:13:09.000000000 -0700 | |
291 | +++ usr/src/nv.2286310/nv.c 2008-03-16 14:37:47.208131723 -0700 | |
292 | @@ -15,6 +15,7 @@ | |
293 | #include "nv_compiler.h" | |
294 | #include "os-agp.h" | |
295 | #include "nv-vm.h" | |
296 | +#include "nv-reg.h" | |
297 | ||
298 | #ifdef MODULE_ALIAS_CHARDEV_MAJOR | |
299 | MODULE_ALIAS_CHARDEV_MAJOR(NV_MAJOR_DEVICE_NUMBER); | |
300 | @@ -116,10 +117,7 @@ | |
301 | unsigned int nv_remap_limit; | |
302 | #endif | |
303 | ||
304 | -#if defined(NV_CHANGE_PAGE_ATTR_PRESENT) | |
305 | -int nv_use_cpa = 1; | |
306 | -#endif | |
307 | - | |
308 | +int nv_update_memory_types = 1; | |
309 | static int nv_mmconfig_failure_detected = 0; | |
310 | ||
311 | static void *nv_pte_t_cache = NULL; | |
312 | @@ -1030,30 +1028,26 @@ | |
313 | #endif /* defined(NV_BUILD_NV_PAT_SUPPORT) */ | |
314 | } | |
315 | ||
316 | - | |
317 | #if defined(NV_CHANGE_PAGE_ATTR_BUG_PRESENT) | |
318 | - | |
319 | -/* nv_verify_cpa_interface - determine if the change_page_attr bug is fixed | |
320 | - * in this kernel. | |
321 | +/* | |
322 | + * nv_verify_cpa_interface() - determine if the change_page_attr() large page | |
323 | + * management accounting bug known to exist in early Linux/x86-64 kernels | |
324 | + * is present in this kernel. | |
325 | * | |
326 | - * there's really not a good way to determine if change_page_attr is fixed. | |
327 | - * we can't really use cpa on 2.6 x86_64 kernels < 2.6.11, as if we run into | |
328 | - * the accounting bug, the kernel will throw a BUG. this isn't 100% accurate, | |
329 | - * as it doesn't throw a bug until we try to restore the caching attributes | |
330 | - * of the page. so if we can track down a 4M allocation, we can mark it | |
331 | - * uncached and see if the accounting was done correctly. | |
332 | - * | |
333 | - * this is a little ugly, but the most accurate approach to determining if | |
334 | - * this kernel is good. | |
335 | + * There's really no good way to determine if change_page_attr() is working | |
336 | + * correctly. We can't reliably use change_page_attr() on Linux/x86-64 2.6 | |
337 | + * kernels < 2.6.11: if we run into the accounting bug, the Linux kernel will | |
338 | + * trigger a BUG() if we attempt to restore the WB memory type of a page | |
339 | + * originally part of a large page. | |
340 | * | |
341 | - * why do we even bother? some distributions have back-ported the cpa fix to | |
342 | - * kernels < 2.6.11. we want to use change_page_attr to avoid random corruption | |
343 | - * and hangs, but need to make sure it's safe to do so. | |
344 | + * So if we can successfully allocate such a page, change its memory type to | |
345 | + * UC and check if the accounting was done correctly, we can determine if | |
346 | + * the change_page_attr() interface can be used safely. | |
347 | * | |
348 | - * return values: | |
349 | - * 0 - test passed, interface works | |
350 | - * 1 - test failed, status unclear | |
351 | - * -1 - test failed, interface broken | |
352 | + * Return values: | |
353 | + * 0 - test passed, the change_page_attr() interface works | |
354 | + * 1 - test failed, the status is unclear | |
355 | + * -1 - test failed, the change_page_attr() interface is broken | |
356 | */ | |
357 | ||
358 | static inline pte_t *check_large_page(unsigned long vaddr) | |
359 | @@ -1061,7 +1055,7 @@ | |
360 | pgd_t *pgd = NULL; | |
361 | pmd_t *pmd = NULL; | |
362 | ||
363 | - pgd = NV_PGD_OFFSET(vaddr, 1, &init_mm); | |
364 | + pgd = NV_PGD_OFFSET(vaddr, 1, NULL); | |
365 | if (!NV_PGD_PRESENT(pgd)) | |
366 | return NULL; | |
367 | ||
368 | @@ -1171,20 +1165,29 @@ | |
369 | ||
370 | return 1; | |
371 | } | |
372 | - | |
373 | #endif /* defined(NV_CHANGE_PAGE_ATTR_BUG_PRESENT) */ | |
374 | ||
375 | - | |
376 | -// verify that the kernel's mapping matches the requested type | |
377 | -// this is to protect against accidental cache aliasing problems | |
378 | +/* | |
379 | + * nv_verify_page_mappings() - verify that the kernel mapping of the specified | |
380 | + * page matches the specified type. This is to help detect bugs in the Linux | |
381 | + * kernel's change_page_attr() interface, early. | |
382 | + * | |
383 | + * This function relies on the ability to perform kernel virtul address to PFN | |
384 | + * translations and therefore on 'init_mm'. Unfortunately, the latter is no | |
385 | + * longer exported in recent Linux/x86 2.6 kernels. The export was removed at | |
386 | + * roughtly the same time as the set_pages_{uc,wb}() change_page_attr() | |
387 | + * replacement interfaces were introduced; hopefully, it will be sufficient to | |
388 | + * check for their presence. | |
389 | + */ | |
390 | int nv_verify_page_mappings( | |
391 | nv_pte_t *page_ptr, | |
392 | unsigned int cachetype | |
393 | ) | |
394 | { | |
395 | +#if defined(NV_CHANGE_PAGE_ATTR_PRESENT) || \ | |
396 | + (defined(NV_SET_PAGES_UC_PRESENT) && !defined(NVCPU_X86)) | |
397 | unsigned long retval = -1; | |
398 | #if defined(NVCPU_X86) || defined(NVCPU_X86_64) | |
399 | - struct mm_struct *mm; | |
400 | pgd_t *pgd = NULL; | |
401 | pmd_t *pmd = NULL; | |
402 | pte_t *pte = NULL; | |
403 | @@ -1192,15 +1195,12 @@ | |
404 | unsigned long address; | |
405 | static int count = 0; | |
406 | ||
407 | -#if defined(NV_CHANGE_PAGE_ATTR_PRESENT) | |
408 | - if (!nv_use_cpa) | |
409 | + if (!nv_update_memory_types) | |
410 | return 0; | |
411 | -#endif | |
412 | ||
413 | address = (unsigned long)__va(page_ptr->phys_addr); | |
414 | - mm = &init_mm; // always a kernel page | |
415 | ||
416 | - pgd = NV_PGD_OFFSET(address, 1, mm); | |
417 | + pgd = NV_PGD_OFFSET(address, 1, NULL); | |
418 | if (!NV_PGD_PRESENT(pgd)) | |
419 | { | |
420 | nv_printf(NV_DBG_ERRORS, "NVRM: pgd not present for addr 0x%lx\n", address); | |
421 | @@ -1266,8 +1266,11 @@ | |
422 | } | |
423 | ||
424 | failed: | |
425 | -#endif | |
426 | +#endif /* defined(NVCPU_X86) || defined(NVCPU_X86_64) */ | |
427 | return retval; | |
428 | +#else | |
429 | + return 0; | |
430 | +#endif | |
431 | } | |
432 | ||
433 | #if defined(NV_BUILD_NV_PAT_SUPPORT) && defined(CONFIG_HOTPLUG_CPU) | |
434 | @@ -1313,7 +1316,7 @@ | |
435 | static int __init nvidia_init_module(void) | |
436 | { | |
437 | int rc; | |
438 | - U032 i, count; | |
439 | + U032 i, count, data; | |
440 | nv_state_t *nv = NV_STATE_PTR(&nv_ctl_device); | |
441 | nv_stack_t *sp = NULL; | |
442 | ||
443 | @@ -1485,43 +1488,42 @@ | |
444 | /* create /proc/driver/nvidia */ | |
445 | nvos_proc_create(); | |
446 | ||
447 | -#if defined(NV_CHANGE_PAGE_ATTR_PRESENT) | |
448 | + /* | |
449 | + * Give users an opportunity to disable the driver's use of | |
450 | + * the change_page_attr() and set_pages_{uc,wb}() kernel | |
451 | + * interfaces. | |
452 | + */ | |
453 | + rc = rm_read_registry_dword(sp, nv, | |
454 | + "NVreg", NV_REG_UPDATE_MEMORY_TYPES, &data); | |
455 | + if ((rc == 0) && ((int)data != ~0)) | |
456 | { | |
457 | - int data; | |
458 | - | |
459 | - // allow the user to override us with a registry key | |
460 | - rc = rm_read_registry_dword(sp, nv, "NVreg", "UseCPA", &data); | |
461 | - if ((rc == 0) && (data != -1)) | |
462 | - { | |
463 | - nv_use_cpa = data; | |
464 | - } | |
465 | + nv_update_memory_types = data; | |
466 | + } | |
467 | #if defined(NV_CHANGE_PAGE_ATTR_BUG_PRESENT) | |
468 | - else | |
469 | + /* | |
470 | + * Unless we explicitely detect that the change_page_attr() | |
471 | + * inteface is fixed, disable usage of the interface on | |
472 | + * this kernel. Notify the user of this problem using the | |
473 | + * driver's /proc warnings interface (read by the installer | |
474 | + * and the bug report script). | |
475 | + */ | |
476 | + else | |
477 | + { | |
478 | + rc = nv_verify_cpa_interface(); | |
479 | + if (rc < 0) | |
480 | { | |
481 | - /* | |
482 | - * Unless we explicitely detect that the change_page_attr() | |
483 | - * inteface is fixed, disable usage of the interface on | |
484 | - * this kernel. Notify the user of this problem using the | |
485 | - * driver's /proc warnings interface (read by the installer | |
486 | - * and the bug report script). | |
487 | - */ | |
488 | - rc = nv_verify_cpa_interface(); | |
489 | - if (rc < 0) | |
490 | - { | |
491 | - nv_prints(NV_DBG_ERRORS, __cpgattr_warning); | |
492 | - nvos_proc_add_warning_file("change_page_attr", __cpgattr_warning); | |
493 | - nv_use_cpa = 0; | |
494 | - } | |
495 | - else if (rc != 0) | |
496 | - { | |
497 | - nv_prints(NV_DBG_ERRORS, __cpgattr_warning_2); | |
498 | - nvos_proc_add_warning_file("change_page_attr", __cpgattr_warning_2); | |
499 | - nv_use_cpa = 0; | |
500 | - } | |
501 | + nv_prints(NV_DBG_ERRORS, __cpgattr_warning); | |
502 | + nvos_proc_add_warning_file("change_page_attr", __cpgattr_warning); | |
503 | + nv_update_memory_types = 0; | |
504 | + } | |
505 | + else if (rc != 0) | |
506 | + { | |
507 | + nv_prints(NV_DBG_ERRORS, __cpgattr_warning_2); | |
508 | + nvos_proc_add_warning_file("change_page_attr", __cpgattr_warning_2); | |
509 | + nv_update_memory_types = 0; | |
510 | } | |
511 | -#endif | |
512 | } | |
513 | -#endif | |
514 | +#endif /* defined(NV_CHANGE_PAGE_ATTR_BUG_PRESENT) */ | |
515 | ||
516 | #if defined(NVCPU_X86_64) && defined(CONFIG_IA32_EMULATION) && !defined(HAVE_COMPAT_IOCTL) | |
517 | /* Register ioctl()'s for 32-bit clients */ | |
518 | @@ -3482,8 +3484,21 @@ | |
519 | pte_t *pte = NULL; | |
520 | NvU64 retval; | |
521 | ||
522 | - mm = (kern) ? &init_mm : current->mm; | |
523 | - if (!kern) down_read(¤t->mm->mmap_sem); | |
524 | + if (!kern) | |
525 | + { | |
526 | + mm = current->mm; | |
527 | + down_read(&mm->mmap_sem); | |
528 | + } | |
529 | + else | |
530 | + { | |
531 | +#if defined(NV_SET_PAGES_UC_PRESENT) && defined(NVCPU_X86) | |
532 | + /* nv_printf(NV_DBG_ERRORS, | |
533 | + "NVRM: can't translate KVA in nv_get_phys_address()!\n"); */ | |
534 | + return 0; | |
535 | +#else | |
536 | + mm = NULL; | |
537 | +#endif | |
538 | + } | |
539 | ||
540 | pgd = NV_PGD_OFFSET(address, kern, mm); | |
541 | if (!NV_PGD_PRESENT(pgd)) | |
542 | @@ -3504,22 +3519,24 @@ | |
543 | retval &= ~_PAGE_NX; | |
544 | #endif | |
545 | ||
546 | - if (!kern) up_read(¤t->mm->mmap_sem); | |
547 | + if (!kern) | |
548 | + up_read(&mm->mmap_sem); | |
549 | return retval; | |
550 | ||
551 | failed: | |
552 | - if (!kern) up_read(¤t->mm->mmap_sem); | |
553 | + if (!kern) | |
554 | + up_read(&mm->mmap_sem); | |
555 | return 0; | |
556 | } | |
557 | ||
558 | NvU64 NV_API_CALL nv_get_kern_phys_address(NvU64 address) | |
559 | { | |
560 | - // make sure this address is a kernel pointer | |
561 | + /* make sure this address is a kernel virtual address */ | |
562 | #if defined(DEBUG) && !defined(CONFIG_X86_4G) | |
563 | if (address < PAGE_OFFSET) | |
564 | { | |
565 | nv_printf(NV_DBG_WARNINGS, | |
566 | - "NVRM: user address passed to get_kern_phys_address: 0x%lx\n", | |
567 | + "NVRM: user address passed to get_kern_phys_address: 0x%llx!\n", | |
568 | address); | |
569 | return 0; | |
570 | } | |
571 | @@ -3534,12 +3551,12 @@ | |
572 | ||
573 | NvU64 NV_API_CALL nv_get_kern_user_address(NvU64 address) | |
574 | { | |
575 | - // make sure this address is not a kernel pointer | |
576 | + /* make sure this address is not a kernel virtual address */ | |
577 | #if defined(DEBUG) && !defined(CONFIG_X86_4G) | |
578 | if (address >= PAGE_OFFSET) | |
579 | { | |
580 | nv_printf(NV_DBG_WARNINGS, | |
581 | - "NVRM: kernel address passed to get_user_phys_address: 0x%lx\n", | |
582 | + "NVRM: kernel address passed to get_user_phys_address: 0x%llx!\n", | |
583 | address); | |
584 | return 0; | |
585 | } | |
586 | @@ -4316,16 +4333,12 @@ | |
587 | return -1; | |
588 | } | |
589 | ||
590 | -int NV_API_CALL nv_no_incoherent_mappings | |
591 | -( | |
592 | - void | |
593 | -) | |
594 | +int NV_API_CALL nv_no_incoherent_mappings(void) | |
595 | { | |
596 | if(nv_ext_no_incoherent_mappings() == 1) | |
597 | return 1; | |
598 | - | |
599 | -#if defined(NV_CHANGE_PAGE_ATTR_PRESENT) | |
600 | - return 1; | |
601 | +#if defined(NV_CHANGE_PAGE_ATTR_PRESENT) || defined(NV_SET_PAGES_UC_PRESENT) | |
602 | + return (nv_update_memory_types); | |
603 | #else | |
604 | return 0; | |
605 | #endif | |
606 | diff -ru usr/src/nv/os-interface.c usr/src/nv.2286310/os-interface.c | |
607 | --- usr/src/nv/os-interface.c 2008-03-16 14:13:09.000000000 -0700 | |
608 | +++ usr/src/nv.2286310/os-interface.c 2008-03-16 14:37:47.208131723 -0700 | |
609 | @@ -1198,6 +1198,18 @@ | |
610 | { | |
611 | void *vaddr; | |
612 | ||
613 | + if (start == 0) | |
614 | + { | |
615 | + if (mode != NV_MEMORY_CACHED) | |
616 | + { | |
617 | + nv_printf(NV_DBG_ERRORS, | |
618 | + "NVRM: os_map_kernel_space: won't map address 0x%0llx UC!\n", start); | |
619 | + return NULL; | |
620 | + } | |
621 | + else | |
622 | + return (void *)PAGE_OFFSET; | |
623 | + } | |
624 | + | |
625 | if (!NV_MAY_SLEEP()) | |
626 | { | |
627 | nv_printf(NV_DBG_ERRORS, | |
628 | @@ -1230,6 +1242,9 @@ | |
629 | NvU64 size_bytes | |
630 | ) | |
631 | { | |
632 | + if (addr == (void *)PAGE_OFFSET) | |
633 | + return; | |
634 | + | |
635 | NV_IOUNMAP(addr, size_bytes); | |
636 | } | |
637 |