x86: mtrr: Update MTRRs on all CPUs
[pandora-u-boot.git] / arch / x86 / cpu / mtrr.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * (C) Copyright 2014 Google, Inc
4  *
5  * Memory Type Range Regsters - these are used to tell the CPU whether
6  * memory is cacheable and if so the cache write mode to use.
7  *
8  * These can speed up booting. See the mtrr command.
9  *
10  * Reference: Intel Architecture Software Developer's Manual, Volume 3:
11  * System Programming
12  */
13
14 /*
15  * Note that any console output (e.g. debug()) in this file will likely fail
16  * since the MTRR registers are sometimes in flux.
17  */
18
19 #include <common.h>
20 #include <cpu_func.h>
21 #include <log.h>
22 #include <asm/cache.h>
23 #include <asm/io.h>
24 #include <asm/mp.h>
25 #include <asm/msr.h>
26 #include <asm/mtrr.h>
27
28 DECLARE_GLOBAL_DATA_PTR;
29
30 /* Prepare to adjust MTRRs */
31 void mtrr_open(struct mtrr_state *state, bool do_caches)
32 {
33         if (!gd->arch.has_mtrr)
34                 return;
35
36         if (do_caches) {
37                 state->enable_cache = dcache_status();
38
39                 if (state->enable_cache)
40                         disable_caches();
41         }
42         state->deftype = native_read_msr(MTRR_DEF_TYPE_MSR);
43         wrmsrl(MTRR_DEF_TYPE_MSR, state->deftype & ~MTRR_DEF_TYPE_EN);
44 }
45
46 /* Clean up after adjusting MTRRs, and enable them */
47 void mtrr_close(struct mtrr_state *state, bool do_caches)
48 {
49         if (!gd->arch.has_mtrr)
50                 return;
51
52         wrmsrl(MTRR_DEF_TYPE_MSR, state->deftype | MTRR_DEF_TYPE_EN);
53         if (do_caches && state->enable_cache)
54                 enable_caches();
55 }
56
57 static void set_var_mtrr(uint reg, uint type, uint64_t start, uint64_t size)
58 {
59         u64 mask;
60
61         wrmsrl(MTRR_PHYS_BASE_MSR(reg), start | type);
62         mask = ~(size - 1);
63         mask &= (1ULL << CONFIG_CPU_ADDR_BITS) - 1;
64         wrmsrl(MTRR_PHYS_MASK_MSR(reg), mask | MTRR_PHYS_MASK_VALID);
65 }
66
67 void mtrr_read_all(struct mtrr_info *info)
68 {
69         int i;
70
71         for (i = 0; i < MTRR_COUNT; i++) {
72                 info->mtrr[i].base = native_read_msr(MTRR_PHYS_BASE_MSR(i));
73                 info->mtrr[i].mask = native_read_msr(MTRR_PHYS_MASK_MSR(i));
74         }
75 }
76
77 void mtrr_write_all(struct mtrr_info *info)
78 {
79         struct mtrr_state state;
80         int i;
81
82         for (i = 0; i < MTRR_COUNT; i++) {
83                 mtrr_open(&state, true);
84                 wrmsrl(MTRR_PHYS_BASE_MSR(i), info->mtrr[i].base);
85                 wrmsrl(MTRR_PHYS_MASK_MSR(i), info->mtrr[i].mask);
86                 mtrr_close(&state, true);
87         }
88 }
89
90 static void write_mtrrs(void *arg)
91 {
92         struct mtrr_info *info = arg;
93
94         mtrr_write_all(info);
95 }
96
97 static void read_mtrrs(void *arg)
98 {
99         struct mtrr_info *info = arg;
100
101         mtrr_read_all(info);
102 }
103
104 /**
105  * mtrr_copy_to_aps() - Copy the MTRRs from the boot CPU to other CPUs
106  *
107  * @return 0 on success, -ve on failure
108  */
109 static int mtrr_copy_to_aps(void)
110 {
111         struct mtrr_info info;
112         int ret;
113
114         ret = mp_run_on_cpus(MP_SELECT_BSP, read_mtrrs, &info);
115         if (ret == -ENXIO)
116                 return 0;
117         else if (ret)
118                 return log_msg_ret("bsp", ret);
119
120         ret = mp_run_on_cpus(MP_SELECT_APS, write_mtrrs, &info);
121         if (ret)
122                 return log_msg_ret("bsp", ret);
123
124         return 0;
125 }
126
127 int mtrr_commit(bool do_caches)
128 {
129         struct mtrr_request *req = gd->arch.mtrr_req;
130         struct mtrr_state state;
131         int ret;
132         int i;
133
134         debug("%s: enabled=%d, count=%d\n", __func__, gd->arch.has_mtrr,
135               gd->arch.mtrr_req_count);
136         if (!gd->arch.has_mtrr)
137                 return -ENOSYS;
138
139         debug("open\n");
140         mtrr_open(&state, do_caches);
141         debug("open done\n");
142         for (i = 0; i < gd->arch.mtrr_req_count; i++, req++)
143                 set_var_mtrr(i, req->type, req->start, req->size);
144
145         /* Clear the ones that are unused */
146         debug("clear\n");
147         for (; i < MTRR_COUNT; i++)
148                 wrmsrl(MTRR_PHYS_MASK_MSR(i), 0);
149         debug("close\n");
150         mtrr_close(&state, do_caches);
151         debug("mtrr done\n");
152
153         if (gd->flags & GD_FLG_RELOC) {
154                 ret = mtrr_copy_to_aps();
155                 if (ret)
156                         return log_msg_ret("copy", ret);
157         }
158
159         return 0;
160 }
161
162 int mtrr_add_request(int type, uint64_t start, uint64_t size)
163 {
164         struct mtrr_request *req;
165         uint64_t mask;
166
167         debug("%s: count=%d\n", __func__, gd->arch.mtrr_req_count);
168         if (!gd->arch.has_mtrr)
169                 return -ENOSYS;
170
171         if (gd->arch.mtrr_req_count == MAX_MTRR_REQUESTS)
172                 return -ENOSPC;
173         req = &gd->arch.mtrr_req[gd->arch.mtrr_req_count++];
174         req->type = type;
175         req->start = start;
176         req->size = size;
177         debug("%d: type=%d, %08llx  %08llx\n", gd->arch.mtrr_req_count - 1,
178               req->type, req->start, req->size);
179         mask = ~(req->size - 1);
180         mask &= (1ULL << CONFIG_CPU_ADDR_BITS) - 1;
181         mask |= MTRR_PHYS_MASK_VALID;
182         debug("   %016llx %016llx\n", req->start | req->type, mask);
183
184         return 0;
185 }
186
187 static int get_var_mtrr_count(void)
188 {
189         return msr_read(MSR_MTRR_CAP_MSR).lo & MSR_MTRR_CAP_VCNT;
190 }
191
192 static int get_free_var_mtrr(void)
193 {
194         struct msr_t maskm;
195         int vcnt;
196         int i;
197
198         vcnt = get_var_mtrr_count();
199
200         /* Identify the first var mtrr which is not valid */
201         for (i = 0; i < vcnt; i++) {
202                 maskm = msr_read(MTRR_PHYS_MASK_MSR(i));
203                 if ((maskm.lo & MTRR_PHYS_MASK_VALID) == 0)
204                         return i;
205         }
206
207         /* No free var mtrr */
208         return -ENOSPC;
209 }
210
211 int mtrr_set_next_var(uint type, uint64_t start, uint64_t size)
212 {
213         int mtrr;
214
215         mtrr = get_free_var_mtrr();
216         if (mtrr < 0)
217                 return mtrr;
218
219         set_var_mtrr(mtrr, type, start, size);
220         debug("MTRR %x: start=%x, size=%x\n", mtrr, (uint)start, (uint)size);
221
222         return 0;
223 }