cyrix.c 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. #include <linux/init.h>
  2. #include <linux/io.h>
  3. #include <linux/mm.h>
  4. #include <asm/processor-cyrix.h>
  5. #include <asm/processor-flags.h>
  6. #include <asm/mtrr.h>
  7. #include <asm/msr.h>
  8. #include "mtrr.h"
  9. static void
  10. cyrix_get_arr(unsigned int reg, unsigned long *base,
  11. unsigned long *size, mtrr_type * type)
  12. {
  13. unsigned char arr, ccr3, rcr, shift;
  14. unsigned long flags;
  15. arr = CX86_ARR_BASE + (reg << 1) + reg; /* avoid multiplication by 3 */
  16. local_irq_save(flags);
  17. ccr3 = getCx86(CX86_CCR3);
  18. setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); /* enable MAPEN */
  19. ((unsigned char *)base)[3] = getCx86(arr);
  20. ((unsigned char *)base)[2] = getCx86(arr + 1);
  21. ((unsigned char *)base)[1] = getCx86(arr + 2);
  22. rcr = getCx86(CX86_RCR_BASE + reg);
  23. setCx86(CX86_CCR3, ccr3); /* disable MAPEN */
  24. local_irq_restore(flags);
  25. shift = ((unsigned char *) base)[1] & 0x0f;
  26. *base >>= PAGE_SHIFT;
  27. /*
  28. * Power of two, at least 4K on ARR0-ARR6, 256K on ARR7
  29. * Note: shift==0xf means 4G, this is unsupported.
  30. */
  31. if (shift)
  32. *size = (reg < 7 ? 0x1UL : 0x40UL) << (shift - 1);
  33. else
  34. *size = 0;
  35. /* Bit 0 is Cache Enable on ARR7, Cache Disable on ARR0-ARR6 */
  36. if (reg < 7) {
  37. switch (rcr) {
  38. case 1:
  39. *type = MTRR_TYPE_UNCACHABLE;
  40. break;
  41. case 8:
  42. *type = MTRR_TYPE_WRBACK;
  43. break;
  44. case 9:
  45. *type = MTRR_TYPE_WRCOMB;
  46. break;
  47. case 24:
  48. default:
  49. *type = MTRR_TYPE_WRTHROUGH;
  50. break;
  51. }
  52. } else {
  53. switch (rcr) {
  54. case 0:
  55. *type = MTRR_TYPE_UNCACHABLE;
  56. break;
  57. case 8:
  58. *type = MTRR_TYPE_WRCOMB;
  59. break;
  60. case 9:
  61. *type = MTRR_TYPE_WRBACK;
  62. break;
  63. case 25:
  64. default:
  65. *type = MTRR_TYPE_WRTHROUGH;
  66. break;
  67. }
  68. }
  69. }
  70. /*
  71. * cyrix_get_free_region - get a free ARR.
  72. *
  73. * @base: the starting (base) address of the region.
  74. * @size: the size (in bytes) of the region.
  75. *
  76. * Returns: the index of the region on success, else -1 on error.
  77. */
  78. static int
  79. cyrix_get_free_region(unsigned long base, unsigned long size, int replace_reg)
  80. {
  81. unsigned long lbase, lsize;
  82. mtrr_type ltype;
  83. int i;
  84. switch (replace_reg) {
  85. case 7:
  86. if (size < 0x40)
  87. break;
  88. case 6:
  89. case 5:
  90. case 4:
  91. return replace_reg;
  92. case 3:
  93. case 2:
  94. case 1:
  95. case 0:
  96. return replace_reg;
  97. }
  98. /* If we are to set up a region >32M then look at ARR7 immediately */
  99. if (size > 0x2000) {
  100. cyrix_get_arr(7, &lbase, &lsize, &ltype);
  101. if (lsize == 0)
  102. return 7;
  103. /* Else try ARR0-ARR6 first */
  104. } else {
  105. for (i = 0; i < 7; i++) {
  106. cyrix_get_arr(i, &lbase, &lsize, &ltype);
  107. if (lsize == 0)
  108. return i;
  109. }
  110. /*
  111. * ARR0-ARR6 isn't free
  112. * try ARR7 but its size must be at least 256K
  113. */
  114. cyrix_get_arr(i, &lbase, &lsize, &ltype);
  115. if ((lsize == 0) && (size >= 0x40))
  116. return i;
  117. }
  118. return -ENOSPC;
  119. }
  120. static u32 cr4, ccr3;
  121. static void prepare_set(void)
  122. {
  123. u32 cr0;
  124. /* Save value of CR4 and clear Page Global Enable (bit 7) */
  125. if (cpu_has_pge) {
  126. cr4 = read_cr4();
  127. write_cr4(cr4 & ~X86_CR4_PGE);
  128. }
  129. /*
  130. * Disable and flush caches.
  131. * Note that wbinvd flushes the TLBs as a side-effect
  132. */
  133. cr0 = read_cr0() | X86_CR0_CD;
  134. wbinvd();
  135. write_cr0(cr0);
  136. wbinvd();
  137. /* Cyrix ARRs - everything else was excluded at the top */
  138. ccr3 = getCx86(CX86_CCR3);
  139. /* Cyrix ARRs - everything else was excluded at the top */
  140. setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10);
  141. }
  142. static void post_set(void)
  143. {
  144. /* Flush caches and TLBs */
  145. wbinvd();
  146. /* Cyrix ARRs - everything else was excluded at the top */
  147. setCx86(CX86_CCR3, ccr3);
  148. /* Enable caches */
  149. write_cr0(read_cr0() & 0xbfffffff);
  150. /* Restore value of CR4 */
  151. if (cpu_has_pge)
  152. write_cr4(cr4);
  153. }
  154. static void cyrix_set_arr(unsigned int reg, unsigned long base,
  155. unsigned long size, mtrr_type type)
  156. {
  157. unsigned char arr, arr_type, arr_size;
  158. arr = CX86_ARR_BASE + (reg << 1) + reg; /* avoid multiplication by 3 */
  159. /* count down from 32M (ARR0-ARR6) or from 2G (ARR7) */
  160. if (reg >= 7)
  161. size >>= 6;
  162. size &= 0x7fff; /* make sure arr_size <= 14 */
  163. for (arr_size = 0; size; arr_size++, size >>= 1)
  164. ;
  165. if (reg < 7) {
  166. switch (type) {
  167. case MTRR_TYPE_UNCACHABLE:
  168. arr_type = 1;
  169. break;
  170. case MTRR_TYPE_WRCOMB:
  171. arr_type = 9;
  172. break;
  173. case MTRR_TYPE_WRTHROUGH:
  174. arr_type = 24;
  175. break;
  176. default:
  177. arr_type = 8;
  178. break;
  179. }
  180. } else {
  181. switch (type) {
  182. case MTRR_TYPE_UNCACHABLE:
  183. arr_type = 0;
  184. break;
  185. case MTRR_TYPE_WRCOMB:
  186. arr_type = 8;
  187. break;
  188. case MTRR_TYPE_WRTHROUGH:
  189. arr_type = 25;
  190. break;
  191. default:
  192. arr_type = 9;
  193. break;
  194. }
  195. }
  196. prepare_set();
  197. base <<= PAGE_SHIFT;
  198. setCx86(arr + 0, ((unsigned char *)&base)[3]);
  199. setCx86(arr + 1, ((unsigned char *)&base)[2]);
  200. setCx86(arr + 2, (((unsigned char *)&base)[1]) | arr_size);
  201. setCx86(CX86_RCR_BASE + reg, arr_type);
  202. post_set();
  203. }
  204. typedef struct {
  205. unsigned long base;
  206. unsigned long size;
  207. mtrr_type type;
  208. } arr_state_t;
  209. static arr_state_t arr_state[8] = {
  210. {0UL, 0UL, 0UL}, {0UL, 0UL, 0UL}, {0UL, 0UL, 0UL}, {0UL, 0UL, 0UL},
  211. {0UL, 0UL, 0UL}, {0UL, 0UL, 0UL}, {0UL, 0UL, 0UL}, {0UL, 0UL, 0UL}
  212. };
  213. static unsigned char ccr_state[7] = { 0, 0, 0, 0, 0, 0, 0 };
  214. static void cyrix_set_all(void)
  215. {
  216. int i;
  217. prepare_set();
  218. /* the CCRs are not contiguous */
  219. for (i = 0; i < 4; i++)
  220. setCx86(CX86_CCR0 + i, ccr_state[i]);
  221. for (; i < 7; i++)
  222. setCx86(CX86_CCR4 + i, ccr_state[i]);
  223. for (i = 0; i < 8; i++) {
  224. cyrix_set_arr(i, arr_state[i].base,
  225. arr_state[i].size, arr_state[i].type);
  226. }
  227. post_set();
  228. }
  229. static struct mtrr_ops cyrix_mtrr_ops = {
  230. .vendor = X86_VENDOR_CYRIX,
  231. .set_all = cyrix_set_all,
  232. .set = cyrix_set_arr,
  233. .get = cyrix_get_arr,
  234. .get_free_region = cyrix_get_free_region,
  235. .validate_add_page = generic_validate_add_page,
  236. .have_wrcomb = positive_have_wrcomb,
  237. };
  238. int __init cyrix_init_mtrr(void)
  239. {
  240. set_mtrr_ops(&cyrix_mtrr_ops);
  241. return 0;
  242. }