amd.c 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  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 void
  8. amd_get_mtrr(unsigned int reg, unsigned long *base,
  9. unsigned long *size, mtrr_type *type)
  10. {
  11. unsigned long low, high;
  12. rdmsr(MSR_K6_UWCCR, low, high);
  13. /* Upper dword is region 1, lower is region 0 */
  14. if (reg == 1)
  15. low = high;
  16. /* The base masks off on the right alignment */
  17. *base = (low & 0xFFFE0000) >> PAGE_SHIFT;
  18. *type = 0;
  19. if (low & 1)
  20. *type = MTRR_TYPE_UNCACHABLE;
  21. if (low & 2)
  22. *type = MTRR_TYPE_WRCOMB;
  23. if (!(low & 3)) {
  24. *size = 0;
  25. return;
  26. }
  27. /*
  28. * This needs a little explaining. The size is stored as an
  29. * inverted mask of bits of 128K granularity 15 bits long offset
  30. * 2 bits.
  31. *
  32. * So to get a size we do invert the mask and add 1 to the lowest
  33. * mask bit (4 as its 2 bits in). This gives us a size we then shift
  34. * to turn into 128K blocks.
  35. *
  36. * eg 111 1111 1111 1100 is 512K
  37. *
  38. * invert 000 0000 0000 0011
  39. * +1 000 0000 0000 0100
  40. * *128K ...
  41. */
  42. low = (~low) & 0x1FFFC;
  43. *size = (low + 4) << (15 - PAGE_SHIFT);
  44. }
  45. /**
  46. * amd_set_mtrr - Set variable MTRR register on the local CPU.
  47. *
  48. * @reg The register to set.
  49. * @base The base address of the region.
  50. * @size The size of the region. If this is 0 the region is disabled.
  51. * @type The type of the region.
  52. *
  53. * Returns nothing.
  54. */
  55. static void
  56. amd_set_mtrr(unsigned int reg, unsigned long base, unsigned long size, mtrr_type type)
  57. {
  58. u32 regs[2];
  59. /*
  60. * Low is MTRR0, High MTRR 1
  61. */
  62. rdmsr(MSR_K6_UWCCR, regs[0], regs[1]);
  63. /*
  64. * Blank to disable
  65. */
  66. if (size == 0) {
  67. regs[reg] = 0;
  68. } else {
  69. /*
  70. * Set the register to the base, the type (off by one) and an
  71. * inverted bitmask of the size The size is the only odd
  72. * bit. We are fed say 512K We invert this and we get 111 1111
  73. * 1111 1011 but if you subtract one and invert you get the
  74. * desired 111 1111 1111 1100 mask
  75. *
  76. * But ~(x - 1) == ~x + 1 == -x. Two's complement rocks!
  77. */
  78. regs[reg] = (-size >> (15 - PAGE_SHIFT) & 0x0001FFFC)
  79. | (base << PAGE_SHIFT) | (type + 1);
  80. }
  81. /*
  82. * The writeback rule is quite specific. See the manual. Its
  83. * disable local interrupts, write back the cache, set the mtrr
  84. */
  85. wbinvd();
  86. wrmsr(MSR_K6_UWCCR, regs[0], regs[1]);
  87. }
  88. static int
  89. amd_validate_add_page(unsigned long base, unsigned long size, unsigned int type)
  90. {
  91. /*
  92. * Apply the K6 block alignment and size rules
  93. * In order
  94. * o Uncached or gathering only
  95. * o 128K or bigger block
  96. * o Power of 2 block
  97. * o base suitably aligned to the power
  98. */
  99. if (type > MTRR_TYPE_WRCOMB || size < (1 << (17 - PAGE_SHIFT))
  100. || (size & ~(size - 1)) - size || (base & (size - 1)))
  101. return -EINVAL;
  102. return 0;
  103. }
  104. static const struct mtrr_ops amd_mtrr_ops = {
  105. .vendor = X86_VENDOR_AMD,
  106. .set = amd_set_mtrr,
  107. .get = amd_get_mtrr,
  108. .get_free_region = generic_get_free_region,
  109. .validate_add_page = amd_validate_add_page,
  110. .have_wrcomb = positive_have_wrcomb,
  111. };
  112. int __init amd_init_mtrr(void)
  113. {
  114. set_mtrr_ops(&amd_mtrr_ops);
  115. return 0;
  116. }