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