Advertisement
Guest User

nv-pat.c

a guest
May 26th, 2015
331
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.41 KB | None | 0 0
  1. /* _NVRM_COPYRIGHT_BEGIN_
  2. *
  3. * Copyright 1999-2011 by NVIDIA Corporation. All rights reserved. All
  4. * information contained herein is proprietary and confidential to NVIDIA
  5. * Corporation. Any use, reproduction, or disclosure without the written
  6. * permission of NVIDIA Corporation is prohibited.
  7. *
  8. * _NVRM_COPYRIGHT_END_
  9. */
  10.  
  11. #define __NO_VERSION__
  12. #include "nv-misc.h"
  13.  
  14. #include "os-interface.h"
  15. #include "nv-linux.h"
  16. #include "nv-reg.h"
  17.  
  18. int nv_pat_mode = NV_PAT_MODE_DISABLED;
  19.  
  20. #if defined(NV_ENABLE_PAT_SUPPORT)
  21. /*
  22. * Private PAT support for use by the NVIDIA driver. This is used on
  23. * kernels that do not modify the PAT to include a write-combining
  24. * entry.
  25. */
  26. static unsigned long orig_pat1, orig_pat2;
  27.  
  28. #define NV_READ_PAT_ENTRIES(pat1, pat2) rdmsr(0x277, (pat1), (pat2))
  29. #define NV_WRITE_PAT_ENTRIES(pat1, pat2) wrmsr(0x277, (pat1), (pat2))
  30. #define NV_PAT_ENTRY(pat, index) \
  31. (((pat) & (0xff << ((index)*8))) >> ((index)*8))
  32.  
  33. static inline void nv_disable_caches(unsigned long *cr4)
  34. {
  35. unsigned long cr0 = read_cr0();
  36. write_cr0(((cr0 & (0xdfffffff)) | 0x40000000));
  37. wbinvd();
  38. #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 4)
  39. *cr4 = read_cr4();
  40. if (*cr4 & 0x80) write_cr4(*cr4 & ~0x80);
  41. __flush_tlb();
  42. #else
  43. *cr4 = __read_cr4();
  44. if (*cr4 & 0x80) __write_cr4(*cr4 & ~0x80);
  45. __flush_tlb();
  46. #endif
  47. }
  48.  
  49. static inline void nv_enable_caches(unsigned long cr4)
  50. {
  51. unsigned long cr0 = read_cr0();
  52. wbinvd();
  53. __flush_tlb();
  54. write_cr0((cr0 & 0x9fffffff));
  55. #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 4)
  56. if (cr4 & 0x80) write_cr4(cr4);
  57. #else
  58. if (cr4 & 0x80) __write_cr4(cr4);
  59. #endif
  60. }
  61.  
  62. static int nv_determine_pat_mode(void)
  63. {
  64. unsigned int pat1, pat2, i;
  65. NvU8 PAT_WC_index;
  66.  
  67. if (!test_bit(X86_FEATURE_PAT,
  68. (volatile unsigned long *)&boot_cpu_data.x86_capability))
  69. {
  70. if ((boot_cpu_data.x86_vendor != X86_VENDOR_INTEL) ||
  71. (boot_cpu_data.cpuid_level < 1) ||
  72. ((cpuid_edx(1) & (1 << 16)) == 0) ||
  73. (boot_cpu_data.x86 != 6) || (boot_cpu_data.x86_model >= 15))
  74. {
  75. nv_printf(NV_DBG_ERRORS,
  76. "NVRM: CPU does not support the PAT.\n");
  77. return NV_PAT_MODE_DISABLED;
  78. }
  79. }
  80.  
  81. NV_READ_PAT_ENTRIES(pat1, pat2);
  82. PAT_WC_index = 0xf;
  83.  
  84. for (i = 0; i < 4; i++)
  85. {
  86. if (NV_PAT_ENTRY(pat1, i) == 0x01)
  87. {
  88. PAT_WC_index = i;
  89. break;
  90. }
  91.  
  92. if (NV_PAT_ENTRY(pat2, i) == 0x01)
  93. {
  94. PAT_WC_index = (i + 4);
  95. break;
  96. }
  97. }
  98.  
  99. if (PAT_WC_index == 1)
  100. return NV_PAT_MODE_KERNEL;
  101. else if (PAT_WC_index != 0xf)
  102. {
  103. nv_printf(NV_DBG_ERRORS,
  104. "NVRM: PAT configuration unsupported.\n");
  105. return NV_PAT_MODE_DISABLED;
  106. }
  107. else
  108. return NV_PAT_MODE_BUILTIN;
  109. }
  110.  
  111. static void nv_setup_pat_entries(void *info)
  112. {
  113. unsigned long pat1, pat2, cr4;
  114. unsigned long eflags;
  115.  
  116. #if defined(NV_ENABLE_HOTPLUG_CPU)
  117. int cpu = (NvUPtr)info;
  118. if ((cpu != 0) && (cpu != (int)smp_processor_id()))
  119. return;
  120. #endif
  121.  
  122. NV_SAVE_FLAGS(eflags);
  123. NV_CLI();
  124. nv_disable_caches(&cr4);
  125.  
  126. NV_READ_PAT_ENTRIES(pat1, pat2);
  127.  
  128. pat1 &= 0xffff00ff;
  129. pat1 |= 0x00000100;
  130.  
  131. NV_WRITE_PAT_ENTRIES(pat1, pat2);
  132.  
  133. nv_enable_caches(cr4);
  134. NV_RESTORE_FLAGS(eflags);
  135. }
  136.  
  137. static void nv_restore_pat_entries(void *info)
  138. {
  139. unsigned long cr4;
  140. unsigned long eflags;
  141.  
  142. #if defined(NV_ENABLE_HOTPLUG_CPU)
  143. int cpu = (NvUPtr)info;
  144. if ((cpu != 0) && (cpu != (int)smp_processor_id()))
  145. return;
  146. #endif
  147.  
  148. NV_SAVE_FLAGS(eflags);
  149. NV_CLI();
  150. nv_disable_caches(&cr4);
  151.  
  152. NV_WRITE_PAT_ENTRIES(orig_pat1, orig_pat2);
  153.  
  154. nv_enable_caches(cr4);
  155. NV_RESTORE_FLAGS(eflags);
  156. }
  157. #endif
  158.  
  159. int nv_enable_pat_support(void)
  160. {
  161. #if defined(NV_ENABLE_PAT_SUPPORT)
  162. unsigned long pat1, pat2;
  163.  
  164. if (nv_pat_mode != NV_PAT_MODE_DISABLED)
  165. return 1;
  166.  
  167. nv_pat_mode = nv_determine_pat_mode();
  168.  
  169. switch (nv_pat_mode)
  170. {
  171. case NV_PAT_MODE_DISABLED:
  172. /* avoid the PAT if unavailable/unusable */
  173. return 0;
  174. case NV_PAT_MODE_KERNEL:
  175. /* inherit the kernel's PAT layout */
  176. return 1;
  177. case NV_PAT_MODE_BUILTIN:
  178. /* use builtin code to modify the PAT layout */
  179. break;
  180. }
  181.  
  182. NV_READ_PAT_ENTRIES(orig_pat1, orig_pat2);
  183. nv_printf(NV_DBG_SETUP, "saved orig pats as 0x%lx 0x%lx\n", orig_pat1, orig_pat2);
  184.  
  185. if (nv_execute_on_all_cpus(nv_setup_pat_entries, NULL) != 0)
  186. {
  187. nv_execute_on_all_cpus(nv_restore_pat_entries, NULL);
  188. return 0;
  189. }
  190.  
  191. NV_READ_PAT_ENTRIES(pat1, pat2);
  192. nv_printf(NV_DBG_SETUP, "changed pats to 0x%lx 0x%lx\n", pat1, pat2);
  193. #endif
  194. return 1;
  195. }
  196.  
  197. void nv_disable_pat_support(void)
  198. {
  199. #if defined(NV_ENABLE_PAT_SUPPORT)
  200. unsigned long pat1, pat2;
  201.  
  202. if (nv_pat_mode != NV_PAT_MODE_BUILTIN)
  203. return;
  204.  
  205. if (nv_execute_on_all_cpus(nv_restore_pat_entries, NULL) != 0)
  206. return;
  207.  
  208. nv_pat_mode = NV_PAT_MODE_DISABLED;
  209.  
  210. NV_READ_PAT_ENTRIES(pat1, pat2);
  211. nv_printf(NV_DBG_SETUP, "restored orig pats as 0x%lx 0x%lx\n", pat1, pat2);
  212. #endif
  213. }
  214.  
  215. #if defined(NV_ENABLE_PAT_SUPPORT) && defined(NV_ENABLE_HOTPLUG_CPU)
  216. static int
  217. nvidia_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
  218. {
  219. unsigned int cpu = get_cpu();
  220.  
  221. switch (action)
  222. {
  223. case CPU_DOWN_FAILED:
  224. case CPU_ONLINE:
  225. if (cpu == (NvUPtr)hcpu)
  226. nv_setup_pat_entries(NULL);
  227. else
  228. NV_SMP_CALL_FUNCTION(nv_setup_pat_entries, hcpu, 1);
  229. break;
  230. case CPU_DOWN_PREPARE:
  231. if (cpu == (NvUPtr)hcpu)
  232. nv_restore_pat_entries(NULL);
  233. else
  234. NV_SMP_CALL_FUNCTION(nv_restore_pat_entries, hcpu, 1);
  235. break;
  236. }
  237.  
  238. put_cpu();
  239.  
  240. return NOTIFY_OK;
  241. }
  242.  
  243. static struct notifier_block nv_hotcpu_nfb = {
  244. .notifier_call = nvidia_cpu_callback,
  245. .priority = 0
  246. };
  247. #endif
  248.  
  249. int nv_init_pat_support(nv_stack_t *sp)
  250. {
  251. RM_STATUS status;
  252. NvU32 data;
  253. int disable_pat = 0;
  254.  
  255. status = rm_read_registry_dword(sp, NULL,
  256. "NVreg", NV_USE_PAGE_ATTRIBUTE_TABLE, &data);
  257. if ((status == RM_OK) && ((int)data != ~0))
  258. {
  259. disable_pat = (data == 0);
  260. }
  261.  
  262. if (!disable_pat)
  263. {
  264. nv_enable_pat_support();
  265. #if defined(NV_ENABLE_PAT_SUPPORT) && defined(NV_ENABLE_HOTPLUG_CPU)
  266. if (nv_pat_mode == NV_PAT_MODE_BUILTIN)
  267. {
  268. if (register_hotcpu_notifier(&nv_hotcpu_nfb) != 0)
  269. {
  270. nv_disable_pat_support();
  271. nv_printf(NV_DBG_ERRORS,
  272. "NVRM: CPU hotplug notifier registration failed!\n");
  273. return -EIO;
  274. }
  275. }
  276. #endif
  277. }
  278. else
  279. {
  280. nv_printf(NV_DBG_ERRORS,
  281. "NVRM: builtin PAT support disabled.\n");
  282. }
  283.  
  284. return 0;
  285. }
  286.  
  287. void nv_teardown_pat_support(void)
  288. {
  289. if (nv_pat_mode == NV_PAT_MODE_BUILTIN)
  290. {
  291. nv_disable_pat_support();
  292. #if defined(NV_ENABLE_PAT_SUPPORT) && defined(NV_ENABLE_HOTPLUG_CPU)
  293. unregister_hotcpu_notifier(&nv_hotcpu_nfb);
  294. #endif
  295. }
  296. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement