ab8cb310e5dfe9fa9da5d9ef1593420daabb155f
[dragonfly.git] / sys / platform / pc32 / acpica5 / acpi_pstate_machdep.c
1 /*
2  * Copyright (c) 2009 The DragonFly Project.  All rights reserved.
3  * 
4  * This code is derived from software contributed to The DragonFly Project
5  * by Sepherosa Ziehau <sepherosa@gmail.com>
6  * 
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  * 3. Neither the name of The DragonFly Project nor the names of its
18  *    contributors may be used to endorse or promote products derived
19  *    from this software without specific, prior written permission.
20  * 
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/globaldata.h>
38
39 #include <machine/md_var.h>
40 #include <machine/cpufunc.h>
41 #include <machine/cpufreq.h>
42 #include <machine/specialreg.h>
43
44 #include "acpi.h"
45 #include "acpi_cpu_pstate.h"
46
47 #define AMD_APMI_HWPSTATE               0x80
48
49 #define AMD_MSR_PSTATE_CSR_MASK         0x7ULL
50 #define AMD1X_MSR_PSTATE_CTL            0xc0010062
51 #define AMD1X_MSR_PSTATE_ST             0xc0010063
52
53 #define AMD_MSR_PSTATE_EN               0x8000000000000000ULL
54
55 #define AMD10_MSR_PSTATE_START          0xc0010064
56 #define AMD10_MSR_PSTATE_COUNT          5
57
58 #define AMD0F_PST_CTL_FID(cval)         (((cval) >> 0)  & 0x3f)
59 #define AMD0F_PST_CTL_VID(cval)         (((cval) >> 6)  & 0x1f)
60 #define AMD0F_PST_CTL_VST(cval)         (((cval) >> 11) & 0x7f)
61 #define AMD0F_PST_CTL_MVS(cval)         (((cval) >> 18) & 0x3)
62 #define AMD0F_PST_CTL_PLLTIME(cval)     (((cval) >> 20) & 0x7f)
63 #define AMD0F_PST_CTL_RVO(cval)         (((cval) >> 28) & 0x3)
64 #define AMD0F_PST_CTL_IRT(cval)         (((cval) >> 30) & 0x3)
65
66 #define AMD0F_PST_ST_FID(sval)          (((sval) >> 0) & 0x3f)
67 #define AMD0F_PST_ST_VID(sval)          (((sval) >> 6) & 0x3f)
68
69 #define INTEL_MSR_MISC_ENABLE           0x1a0
70 #define INTEL_MSR_MISC_EST_EN           0x10000ULL
71
72 #define INTEL_MSR_PERF_STATUS           0x198
73 #define INTEL_MSR_PERF_CTL              0x199
74 #define INTEL_MSR_PERF_MASK             0xffffULL
75
76 static const struct acpi_pst_md *
77                 acpi_pst_amd_probe(void);
78 static int      acpi_pst_amd_check_csr(const struct acpi_pst_res *,
79                     const struct acpi_pst_res *);
80 static int      acpi_pst_amd1x_check_pstates(const struct acpi_pstate *, int,
81                     uint32_t, uint32_t);
82 static int      acpi_pst_amd10_check_pstates(const struct acpi_pstate *, int);
83 static int      acpi_pst_amd0f_check_pstates(const struct acpi_pstate *, int);
84 static int      acpi_pst_amd_init(const struct acpi_pst_res *,
85                     const struct acpi_pst_res *);
86 static int      acpi_pst_amd1x_set_pstate(const struct acpi_pst_res *,
87                     const struct acpi_pst_res *, const struct acpi_pstate *);
88 static int      acpi_pst_amd0f_set_pstate(const struct acpi_pst_res *,
89                     const struct acpi_pst_res *, const struct acpi_pstate *);
90 static const struct acpi_pstate *
91                 acpi_pst_amd1x_get_pstate(const struct acpi_pst_res *,
92                     const struct acpi_pstate *, int);
93 static const struct acpi_pstate *
94                 acpi_pst_amd0f_get_pstate(const struct acpi_pst_res *,
95                     const struct acpi_pstate *, int);
96
97 static const struct acpi_pst_md *
98                 acpi_pst_intel_probe(void);
99 static int      acpi_pst_intel_check_csr(const struct acpi_pst_res *,
100                     const struct acpi_pst_res *);
101 static int      acpi_pst_intel_check_pstates(const struct acpi_pstate *, int);
102 static int      acpi_pst_intel_init(const struct acpi_pst_res *,
103                     const struct acpi_pst_res *);
104 static int      acpi_pst_intel_set_pstate(const struct acpi_pst_res *,
105                     const struct acpi_pst_res *, const struct acpi_pstate *);
106 static const struct acpi_pstate *
107                 acpi_pst_intel_get_pstate(const struct acpi_pst_res *,
108                     const struct acpi_pstate *, int);
109
110 static const struct acpi_pst_md acpi_pst_amd10 = {
111         .pmd_check_csr          = acpi_pst_amd_check_csr,
112         .pmd_check_pstates      = acpi_pst_amd10_check_pstates,
113         .pmd_init               = acpi_pst_amd_init,
114         .pmd_set_pstate         = acpi_pst_amd1x_set_pstate,
115         .pmd_get_pstate         = acpi_pst_amd1x_get_pstate
116 };
117
118 static const struct acpi_pst_md acpi_pst_amd0f = {
119         .pmd_check_csr          = acpi_pst_amd_check_csr,
120         .pmd_check_pstates      = acpi_pst_amd0f_check_pstates,
121         .pmd_init               = acpi_pst_amd_init,
122         .pmd_set_pstate         = acpi_pst_amd0f_set_pstate,
123         .pmd_get_pstate         = acpi_pst_amd0f_get_pstate
124 };
125
126 static const struct acpi_pst_md acpi_pst_intel = {
127         .pmd_check_csr          = acpi_pst_intel_check_csr,
128         .pmd_check_pstates      = acpi_pst_intel_check_pstates,
129         .pmd_init               = acpi_pst_intel_init,
130         .pmd_set_pstate         = acpi_pst_intel_set_pstate,
131         .pmd_get_pstate         = acpi_pst_intel_get_pstate
132 };
133
134 const struct acpi_pst_md *
135 acpi_pst_md_probe(void)
136 {
137         if (strcmp(cpu_vendor, "AuthenticAMD") == 0)
138                 return acpi_pst_amd_probe();
139         else if (strcmp(cpu_vendor, "GenuineIntel") == 0)
140                 return acpi_pst_intel_probe();
141         return NULL;
142 }
143
144 static const struct acpi_pst_md *
145 acpi_pst_amd_probe(void)
146 {
147         uint32_t regs[4], ext_family;
148
149         if ((cpu_id & 0x00000f00) != 0x00000f00)
150                 return NULL;
151
152         /* Check whether APMI exists */
153         do_cpuid(0x80000000, regs);
154         if (regs[0] < 0x80000007)
155                 return NULL;
156
157         /* Fetch APMI */
158         do_cpuid(0x80000007, regs);
159
160         ext_family = cpu_id & 0x0ff00000;
161         switch (ext_family) {
162         case 0x00000000:        /* Family 0fh */
163                 if ((regs[3] & 0x06) == 0x06)
164                         return &acpi_pst_amd0f;
165                 break;
166
167         case 0x00100000:        /* Family 10h */
168                 if (regs[3] & 0x80)
169                         return &acpi_pst_amd10;
170                 break;
171
172         default:
173                 break;
174         }
175         return NULL;
176 }
177
178 static int
179 acpi_pst_amd_check_csr(const struct acpi_pst_res *ctrl,
180                        const struct acpi_pst_res *status)
181 {
182         if (ctrl->pr_gas.SpaceId != ACPI_ADR_SPACE_FIXED_HARDWARE) {
183                 kprintf("cpu%d: Invalid P-State control register\n", mycpuid);
184                 return EINVAL;
185         }
186         if (status->pr_gas.SpaceId != ACPI_ADR_SPACE_FIXED_HARDWARE) {
187                 kprintf("cpu%d: Invalid P-State status register\n", mycpuid);
188                 return EINVAL;
189         }
190         return 0;
191 }
192
193 static int
194 acpi_pst_amd1x_check_pstates(const struct acpi_pstate *pstates, int npstates,
195                              uint32_t msr_start, uint32_t msr_end)
196 {
197         int i;
198
199         /*
200          * Make sure that related MSR P-State registers are enabled.
201          *
202          * NOTE:
203          * We don't check status register value here;
204          * it will not be used.
205          */
206         for (i = 0; i < npstates; ++i) {
207                 uint64_t pstate;
208                 uint32_t msr;
209
210                 msr = msr_start +
211                       (pstates[i].st_cval & AMD_MSR_PSTATE_CSR_MASK);
212                 if (msr >= msr_end) {
213                         kprintf("cpu%d: MSR P-State register %#08x "
214                                 "does not exist\n", mycpuid, msr);
215                         return EINVAL;
216                 }
217
218                 pstate = rdmsr(msr);
219                 if ((pstate & AMD_MSR_PSTATE_EN) == 0) {
220                         kprintf("cpu%d: MSR P-State register %#08x "
221                                 "is not enabled\n", mycpuid, msr);
222                         return EINVAL;
223                 }
224         }
225         return 0;
226 }
227
228 static int
229 acpi_pst_amd10_check_pstates(const struct acpi_pstate *pstates, int npstates)
230 {
231         /* Only P0-P4 are supported */
232         if (npstates > AMD10_MSR_PSTATE_COUNT) {
233                 kprintf("cpu%d: only P0-P4 is allowed\n", mycpuid);
234                 return EINVAL;
235         }
236
237         return acpi_pst_amd1x_check_pstates(pstates, npstates,
238                         AMD10_MSR_PSTATE_START,
239                         AMD10_MSR_PSTATE_START + AMD10_MSR_PSTATE_COUNT);
240 }
241
242 static int
243 acpi_pst_amd1x_set_pstate(const struct acpi_pst_res *ctrl __unused,
244                           const struct acpi_pst_res *status __unused,
245                           const struct acpi_pstate *pstate)
246 {
247         uint64_t cval;
248
249         cval = pstate->st_cval & AMD_MSR_PSTATE_CSR_MASK;
250         wrmsr(AMD1X_MSR_PSTATE_CTL, cval);
251
252         /*
253          * Don't check AMD1X_MSR_PSTATE_ST here, since it is
254          * affected by various P-State limits.
255          *
256          * For details:
257          * AMD Family 10h Processor BKDG Rev 3.20 (#31116)
258          * 2.4.2.4 P-state Transition Behavior
259          */
260
261         return 0;
262 }
263
264 static const struct acpi_pstate *
265 acpi_pst_amd1x_get_pstate(const struct acpi_pst_res *status __unused,
266                           const struct acpi_pstate *pstates, int npstates)
267 {
268         uint64_t sval;
269         int i;
270
271         sval = rdmsr(AMD1X_MSR_PSTATE_ST) & AMD_MSR_PSTATE_CSR_MASK;
272         for (i = 0; i < npstates; ++i) {
273                 if ((pstates[i].st_sval & AMD_MSR_PSTATE_CSR_MASK) == sval)
274                         return &pstates[i];
275         }
276         return NULL;
277 }
278
279 static int
280 acpi_pst_amd0f_check_pstates(const struct acpi_pstate *pstates, int npstates)
281 {
282         struct amd0f_fidvid fv_max, fv_min;
283         int i;
284
285         amd0f_fidvid_limit(&fv_min, &fv_max);
286
287         for (i = 0; i < npstates; ++i) {
288                 const struct acpi_pstate *p = &pstates[i];
289                 uint32_t fid, vid, mvs, rvo;
290                 int mvs_mv, rvo_mv;
291
292                 fid = AMD0F_PST_CTL_FID(p->st_cval);
293                 vid = AMD0F_PST_CTL_VID(p->st_cval);
294
295                 if (fid > fv_max.fid || fid < fv_min.fid) {
296                         kprintf("cpu%d: Invalid FID %#x [%#x, %#x]\n",
297                                 mycpuid, fid, fv_min.fid, fv_max.fid);
298                         return EINVAL;
299                 }
300                 if (vid < fv_max.vid || vid > fv_min.vid) {
301                         kprintf("cpu%d: Invalid VID %#x [%#x, %#x]\n",
302                                 mycpuid, vid, fv_max.vid, fv_min.fid);
303                         return EINVAL;
304                 }
305
306                 mvs = AMD0F_PST_CTL_MVS(p->st_cval);
307                 rvo = AMD0F_PST_CTL_RVO(p->st_cval);
308
309                 /* Only 0 is allowed, i.e. 25mV stepping */
310                 if (mvs != 0) {
311                         kprintf("cpu%d: Invalid MVS %#x\n", mycpuid, mvs);
312                         return EINVAL;
313                 }
314
315                 /* -> mV */
316                 mvs_mv = 25 * (1 << mvs);
317                 rvo_mv = 25 * rvo;
318                 if (rvo_mv % mvs_mv != 0) {
319                         kprintf("cpu%d: Invalid MVS/RVO (%#x/%#x)\n",
320                                 mycpuid, mvs, rvo);
321                         return EINVAL;
322                 }
323         }
324         return 0;
325 }
326
327 static int
328 acpi_pst_amd0f_set_pstate(const struct acpi_pst_res *ctrl __unused,
329                           const struct acpi_pst_res *status __unused,
330                           const struct acpi_pstate *pstate)
331 {
332         struct amd0f_fidvid fv;
333         struct amd0f_xsit xsit;
334
335         fv.fid = AMD0F_PST_CTL_FID(pstate->st_cval);
336         fv.vid = AMD0F_PST_CTL_VID(pstate->st_cval);
337
338         xsit.rvo = AMD0F_PST_CTL_RVO(pstate->st_cval);
339         xsit.mvs = AMD0F_PST_CTL_MVS(pstate->st_cval);
340         xsit.vst = AMD0F_PST_CTL_VST(pstate->st_cval);
341         xsit.pll_time = AMD0F_PST_CTL_PLLTIME(pstate->st_cval);
342         xsit.irt = AMD0F_PST_CTL_IRT(pstate->st_cval);
343
344         return amd0f_set_fidvid(&fv, &xsit);
345 }
346
347 static const struct acpi_pstate *
348 acpi_pst_amd0f_get_pstate(const struct acpi_pst_res *status __unused,
349                           const struct acpi_pstate *pstates, int npstates)
350 {
351         struct amd0f_fidvid fv;
352         int error, i;
353
354         error = amd0f_get_fidvid(&fv);
355         if (error)
356                 return NULL;
357
358         for (i = 0; i < npstates; ++i) {
359                 const struct acpi_pstate *p = &pstates[i];
360
361                 if (fv.fid == AMD0F_PST_ST_FID(p->st_sval) &&
362                     fv.vid == AMD0F_PST_ST_VID(p->st_sval))
363                         return p;
364         }
365         return NULL;
366 }
367
368 static int
369 acpi_pst_amd_init(const struct acpi_pst_res *ctrl __unused,
370                   const struct acpi_pst_res *status __unused)
371 {
372         return 0;
373 }
374
375 static const struct acpi_pst_md *
376 acpi_pst_intel_probe(void)
377 {
378         uint32_t family;
379
380         if ((cpu_feature2 & CPUID2_EST) == 0)
381                 return NULL;
382
383         family = cpu_id & 0xf00;
384         if (family != 0xf00 && family != 0x600)
385                 return NULL;
386         return &acpi_pst_intel;
387 }
388
389 static int
390 acpi_pst_intel_check_csr(const struct acpi_pst_res *ctrl,
391                          const struct acpi_pst_res *status)
392 {
393         if (ctrl->pr_res == NULL) {
394                 if (ctrl->pr_gas.SpaceId != ACPI_ADR_SPACE_FIXED_HARDWARE) {
395                         kprintf("cpu%d: Invalid P-State control register\n",
396                                 mycpuid);
397                         return EINVAL;
398                 }
399         }
400         if (ctrl->pr_gas.SpaceId != status->pr_gas.SpaceId) {
401                 kprintf("cpu%d: P-State control(%d)/status(%d) registers have "
402                         "different SpaceId", mycpuid,
403                         ctrl->pr_gas.SpaceId, status->pr_gas.SpaceId);
404                 return EINVAL;
405         }
406         return 0;
407 }
408
409 static int
410 acpi_pst_intel_check_pstates(const struct acpi_pstate *pstates __unused,
411                              int npstates __unused)
412 {
413         return 0;
414 }
415
416 static int
417 acpi_pst_intel_init(const struct acpi_pst_res *ctrl __unused,
418                     const struct acpi_pst_res *status __unused)
419 {
420         uint32_t family, model;
421         uint64_t misc_enable;
422
423         family = cpu_id & 0xf00;
424         if (family == 0xf00) {
425                 /* EST enable bit is reserved in INTEL_MSR_MISC_ENABLE */
426                 return 0;
427         }
428         KKASSERT(family == 0x600);
429
430         model = ((cpu_id & 0xf0000) >> 12) | ((cpu_id & 0xf0) >> 4);
431         if (model < 0xd) {
432                 /* EST enable bit is reserved in INTEL_MSR_MISC_ENABLE */
433                 return 0;
434         }
435
436         misc_enable = rdmsr(INTEL_MSR_MISC_ENABLE);
437         if ((misc_enable & INTEL_MSR_MISC_EST_EN) == 0) {
438                 misc_enable |= INTEL_MSR_MISC_EST_EN;
439                 wrmsr(INTEL_MSR_MISC_ENABLE, misc_enable);
440
441                 misc_enable = rdmsr(INTEL_MSR_MISC_ENABLE);
442                 if ((misc_enable & INTEL_MSR_MISC_EST_EN) == 0) {
443                         kprintf("cpu%d: Can't enable EST\n", mycpuid);
444                         return EIO;
445                 }
446         }
447         return 0;
448 }
449
450 static int
451 acpi_pst_intel_set_pstate(const struct acpi_pst_res *ctrl,
452                           const struct acpi_pst_res *status __unused,
453                           const struct acpi_pstate *pstate)
454 {
455         uint64_t ctl;
456
457         if (ctrl->pr_res != NULL) {
458                 /* XXX not implemented */
459                 if (mycpuid == 0)
460                         kprintf("%s io not implemented\n", __func__);
461                 return 0;
462         }
463
464         ctl = rdmsr(INTEL_MSR_PERF_CTL);
465         ctl &= ~INTEL_MSR_PERF_MASK;
466         ctl |= (pstate->st_cval & INTEL_MSR_PERF_MASK);
467         wrmsr(INTEL_MSR_PERF_CTL, ctl);
468
469         return 0;
470 }
471
472 static const struct acpi_pstate *
473 acpi_pst_intel_get_pstate(const struct acpi_pst_res *status,
474                           const struct acpi_pstate *pstates, int npstates)
475 {
476         uint64_t sval;
477         int i;
478
479         if (status->pr_res != NULL) {
480                 /* XXX not implemented */
481                 return NULL;
482         }
483
484         sval = rdmsr(INTEL_MSR_PERF_STATUS) & INTEL_MSR_PERF_MASK;
485         for (i = 0; i < npstates; ++i) {
486                 if ((pstates[i].st_sval & INTEL_MSR_PERF_MASK) == sval)
487                         return &pstates[i];
488         }
489         return NULL;
490 }