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