centaur.c 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. #include <linux/init.h>
  2. #include <linux/mm.h>
  3. #include <asm/mtrr.h>
  4. #include <asm/msr.h>
  5. #include "mtrr.h"
  6. static struct {
  7. unsigned long high;
  8. unsigned long low;
  9. } centaur_mcr[8];
  10. static u8 centaur_mcr_reserved;
  11. static u8 centaur_mcr_type; /* 0 for winchip, 1 for winchip2 */
  12. /**
  13. * centaur_get_free_region - Get a free MTRR.
  14. *
  15. * @base: The starting (base) address of the region.
  16. * @size: The size (in bytes) of the region.
  17. *
  18. * Returns: the index of the region on success, else -1 on error.
  19. */
  20. static int
  21. centaur_get_free_region(unsigned long base, unsigned long size, int replace_reg)
  22. {
  23. unsigned long lbase, lsize;
  24. mtrr_type ltype;
  25. int i, max;
  26. max = num_var_ranges;
  27. if (replace_reg >= 0 && replace_reg < max)
  28. return replace_reg;
  29. for (i = 0; i < max; ++i) {
  30. if (centaur_mcr_reserved & (1 << i))
  31. continue;
  32. mtrr_if->get(i, &lbase, &lsize, &ltype);
  33. if (lsize == 0)
  34. return i;
  35. }
  36. return -ENOSPC;
  37. }
  38. /*
  39. * Report boot time MCR setups
  40. */
  41. void mtrr_centaur_report_mcr(int mcr, u32 lo, u32 hi)
  42. {
  43. centaur_mcr[mcr].low = lo;
  44. centaur_mcr[mcr].high = hi;
  45. }
  46. static void
  47. centaur_get_mcr(unsigned int reg, unsigned long *base,
  48. unsigned long *size, mtrr_type * type)
  49. {
  50. *base = centaur_mcr[reg].high >> PAGE_SHIFT;
  51. *size = -(centaur_mcr[reg].low & 0xfffff000) >> PAGE_SHIFT;
  52. *type = MTRR_TYPE_WRCOMB; /* write-combining */
  53. if (centaur_mcr_type == 1 && ((centaur_mcr[reg].low & 31) & 2))
  54. *type = MTRR_TYPE_UNCACHABLE;
  55. if (centaur_mcr_type == 1 && (centaur_mcr[reg].low & 31) == 25)
  56. *type = MTRR_TYPE_WRBACK;
  57. if (centaur_mcr_type == 0 && (centaur_mcr[reg].low & 31) == 31)
  58. *type = MTRR_TYPE_WRBACK;
  59. }
  60. static void
  61. centaur_set_mcr(unsigned int reg, unsigned long base,
  62. unsigned long size, mtrr_type type)
  63. {
  64. unsigned long low, high;
  65. if (size == 0) {
  66. /* Disable */
  67. high = low = 0;
  68. } else {
  69. high = base << PAGE_SHIFT;
  70. if (centaur_mcr_type == 0) {
  71. /* Only support write-combining... */
  72. low = -size << PAGE_SHIFT | 0x1f;
  73. } else {
  74. if (type == MTRR_TYPE_UNCACHABLE)
  75. low = -size << PAGE_SHIFT | 0x02; /* NC */
  76. else
  77. low = -size << PAGE_SHIFT | 0x09; /* WWO, WC */
  78. }
  79. }
  80. centaur_mcr[reg].high = high;
  81. centaur_mcr[reg].low = low;
  82. wrmsr(MSR_IDT_MCR0 + reg, low, high);
  83. }
  84. static int
  85. centaur_validate_add_page(unsigned long base, unsigned long size, unsigned int type)
  86. {
  87. /*
  88. * FIXME: Winchip2 supports uncached
  89. */
  90. if (type != MTRR_TYPE_WRCOMB &&
  91. (centaur_mcr_type == 0 || type != MTRR_TYPE_UNCACHABLE)) {
  92. pr_warn("mtrr: only write-combining%s supported\n",
  93. centaur_mcr_type ? " and uncacheable are" : " is");
  94. return -EINVAL;
  95. }
  96. return 0;
  97. }
  98. static const struct mtrr_ops centaur_mtrr_ops = {
  99. .vendor = X86_VENDOR_CENTAUR,
  100. .set = centaur_set_mcr,
  101. .get = centaur_get_mcr,
  102. .get_free_region = centaur_get_free_region,
  103. .validate_add_page = centaur_validate_add_page,
  104. .have_wrcomb = positive_have_wrcomb,
  105. };
  106. int __init centaur_init_mtrr(void)
  107. {
  108. set_mtrr_ops(&centaur_mtrr_ops);
  109. return 0;
  110. }