centaur.c 3.0 KB

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