2 * Copyright (c) 2009 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Sepherosa Ziehau <sepherosa@gmail.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
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.
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
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/globaldata.h>
39 #include <machine/md_var.h>
40 #include <machine/cpufunc.h>
41 #include <machine/cpufreq.h>
42 #include <machine/cputypes.h>
43 #include <machine/specialreg.h>
46 #include "acpi_cpu_pstate.h"
48 #define AMD_APMI_HWPSTATE 0x80
50 #define AMD_MSR_PSTATE_CSR_MASK 0x7ULL
51 #define AMD1X_MSR_PSTATE_CTL 0xc0010062
52 #define AMD1X_MSR_PSTATE_ST 0xc0010063
54 #define AMD_MSR_PSTATE_EN 0x8000000000000000ULL
56 #define AMD10_MSR_PSTATE_START 0xc0010064
57 #define AMD10_MSR_PSTATE_COUNT 5
59 #define AMD0F_PST_CTL_FID(cval) (((cval) >> 0) & 0x3f)
60 #define AMD0F_PST_CTL_VID(cval) (((cval) >> 6) & 0x1f)
61 #define AMD0F_PST_CTL_VST(cval) (((cval) >> 11) & 0x7f)
62 #define AMD0F_PST_CTL_MVS(cval) (((cval) >> 18) & 0x3)
63 #define AMD0F_PST_CTL_PLLTIME(cval) (((cval) >> 20) & 0x7f)
64 #define AMD0F_PST_CTL_RVO(cval) (((cval) >> 28) & 0x3)
65 #define AMD0F_PST_CTL_IRT(cval) (((cval) >> 30) & 0x3)
67 #define AMD0F_PST_ST_FID(sval) (((sval) >> 0) & 0x3f)
68 #define AMD0F_PST_ST_VID(sval) (((sval) >> 6) & 0x3f)
70 #define INTEL_MSR_MISC_ENABLE 0x1a0
71 #define INTEL_MSR_MISC_EST_EN 0x10000ULL
73 #define INTEL_MSR_PERF_STATUS 0x198
74 #define INTEL_MSR_PERF_CTL 0x199
75 #define INTEL_MSR_PERF_MASK 0xffffULL
77 static const struct acpi_pst_md *
78 acpi_pst_amd_probe(void);
79 static int acpi_pst_amd_check_csr(const struct acpi_pst_res *,
80 const struct acpi_pst_res *);
81 static int acpi_pst_amd1x_check_pstates(const struct acpi_pstate *, int,
83 static int acpi_pst_amd10_check_pstates(const struct acpi_pstate *, int);
84 static int acpi_pst_amd0f_check_pstates(const struct acpi_pstate *, int);
85 static int acpi_pst_amd_init(const struct acpi_pst_res *,
86 const struct acpi_pst_res *);
87 static int acpi_pst_amd1x_set_pstate(const struct acpi_pst_res *,
88 const struct acpi_pst_res *, const struct acpi_pstate *);
89 static int acpi_pst_amd0f_set_pstate(const struct acpi_pst_res *,
90 const struct acpi_pst_res *, const struct acpi_pstate *);
91 static const struct acpi_pstate *
92 acpi_pst_amd1x_get_pstate(const struct acpi_pst_res *,
93 const struct acpi_pstate *, int);
94 static const struct acpi_pstate *
95 acpi_pst_amd0f_get_pstate(const struct acpi_pst_res *,
96 const struct acpi_pstate *, int);
98 static const struct acpi_pst_md *
99 acpi_pst_intel_probe(void);
100 static int acpi_pst_intel_check_csr(const struct acpi_pst_res *,
101 const struct acpi_pst_res *);
102 static int acpi_pst_intel_check_pstates(const struct acpi_pstate *, int);
103 static int acpi_pst_intel_init(const struct acpi_pst_res *,
104 const struct acpi_pst_res *);
105 static int acpi_pst_intel_set_pstate(const struct acpi_pst_res *,
106 const struct acpi_pst_res *, const struct acpi_pstate *);
107 static const struct acpi_pstate *
108 acpi_pst_intel_get_pstate(const struct acpi_pst_res *,
109 const struct acpi_pstate *, int);
111 static int acpi_pst_md_gas_asz(const ACPI_GENERIC_ADDRESS *);
112 static int acpi_pst_md_gas_verify(const ACPI_GENERIC_ADDRESS *);
113 static uint32_t acpi_pst_md_res_read(const struct acpi_pst_res *);
114 static void acpi_pst_md_res_write(const struct acpi_pst_res *, uint32_t);
116 static const struct acpi_pst_md acpi_pst_amd10 = {
117 .pmd_check_csr = acpi_pst_amd_check_csr,
118 .pmd_check_pstates = acpi_pst_amd10_check_pstates,
119 .pmd_init = acpi_pst_amd_init,
120 .pmd_set_pstate = acpi_pst_amd1x_set_pstate,
121 .pmd_get_pstate = acpi_pst_amd1x_get_pstate
124 static const struct acpi_pst_md acpi_pst_amd0f = {
125 .pmd_check_csr = acpi_pst_amd_check_csr,
126 .pmd_check_pstates = acpi_pst_amd0f_check_pstates,
127 .pmd_init = acpi_pst_amd_init,
128 .pmd_set_pstate = acpi_pst_amd0f_set_pstate,
129 .pmd_get_pstate = acpi_pst_amd0f_get_pstate
132 static const struct acpi_pst_md acpi_pst_intel = {
133 .pmd_check_csr = acpi_pst_intel_check_csr,
134 .pmd_check_pstates = acpi_pst_intel_check_pstates,
135 .pmd_init = acpi_pst_intel_init,
136 .pmd_set_pstate = acpi_pst_intel_set_pstate,
137 .pmd_get_pstate = acpi_pst_intel_get_pstate
140 const struct acpi_pst_md *
141 acpi_pst_md_probe(void)
143 if (cpu_vendor_id == CPU_VENDOR_AMD)
144 return acpi_pst_amd_probe();
145 else if (cpu_vendor_id == CPU_VENDOR_INTEL)
146 return acpi_pst_intel_probe();
150 static const struct acpi_pst_md *
151 acpi_pst_amd_probe(void)
153 uint32_t regs[4], ext_family;
155 if ((cpu_id & 0x00000f00) != 0x00000f00)
158 /* Check whether APMI exists */
159 do_cpuid(0x80000000, regs);
160 if (regs[0] < 0x80000007)
164 do_cpuid(0x80000007, regs);
166 ext_family = cpu_id & 0x0ff00000;
167 switch (ext_family) {
168 case 0x00000000: /* Family 0fh */
169 if ((regs[3] & 0x06) == 0x06)
170 return &acpi_pst_amd0f;
173 case 0x00100000: /* Family 10h */
175 return &acpi_pst_amd10;
185 acpi_pst_amd_check_csr(const struct acpi_pst_res *ctrl,
186 const struct acpi_pst_res *status)
188 if (ctrl->pr_gas.SpaceId != ACPI_ADR_SPACE_FIXED_HARDWARE) {
189 kprintf("cpu%d: Invalid P-State control register\n", mycpuid);
192 if (status->pr_gas.SpaceId != ACPI_ADR_SPACE_FIXED_HARDWARE) {
193 kprintf("cpu%d: Invalid P-State status register\n", mycpuid);
200 acpi_pst_amd1x_check_pstates(const struct acpi_pstate *pstates, int npstates,
201 uint32_t msr_start, uint32_t msr_end)
206 * Make sure that related MSR P-State registers are enabled.
209 * We don't check status register value here;
210 * it will not be used.
212 for (i = 0; i < npstates; ++i) {
217 (pstates[i].st_cval & AMD_MSR_PSTATE_CSR_MASK);
218 if (msr >= msr_end) {
219 kprintf("cpu%d: MSR P-State register %#08x "
220 "does not exist\n", mycpuid, msr);
225 if ((pstate & AMD_MSR_PSTATE_EN) == 0) {
226 kprintf("cpu%d: MSR P-State register %#08x "
227 "is not enabled\n", mycpuid, msr);
235 acpi_pst_amd10_check_pstates(const struct acpi_pstate *pstates, int npstates)
237 /* Only P0-P4 are supported */
238 if (npstates > AMD10_MSR_PSTATE_COUNT) {
239 kprintf("cpu%d: only P0-P4 is allowed\n", mycpuid);
243 return acpi_pst_amd1x_check_pstates(pstates, npstates,
244 AMD10_MSR_PSTATE_START,
245 AMD10_MSR_PSTATE_START + AMD10_MSR_PSTATE_COUNT);
249 acpi_pst_amd1x_set_pstate(const struct acpi_pst_res *ctrl __unused,
250 const struct acpi_pst_res *status __unused,
251 const struct acpi_pstate *pstate)
255 cval = pstate->st_cval & AMD_MSR_PSTATE_CSR_MASK;
256 wrmsr(AMD1X_MSR_PSTATE_CTL, cval);
259 * Don't check AMD1X_MSR_PSTATE_ST here, since it is
260 * affected by various P-State limits.
263 * AMD Family 10h Processor BKDG Rev 3.20 (#31116)
264 * 2.4.2.4 P-state Transition Behavior
270 static const struct acpi_pstate *
271 acpi_pst_amd1x_get_pstate(const struct acpi_pst_res *status __unused,
272 const struct acpi_pstate *pstates, int npstates)
277 sval = rdmsr(AMD1X_MSR_PSTATE_ST) & AMD_MSR_PSTATE_CSR_MASK;
278 for (i = 0; i < npstates; ++i) {
279 if ((pstates[i].st_sval & AMD_MSR_PSTATE_CSR_MASK) == sval)
286 acpi_pst_amd0f_check_pstates(const struct acpi_pstate *pstates, int npstates)
288 struct amd0f_fidvid fv_max, fv_min;
291 amd0f_fidvid_limit(&fv_min, &fv_max);
293 for (i = 0; i < npstates; ++i) {
294 const struct acpi_pstate *p = &pstates[i];
295 uint32_t fid, vid, mvs, rvo;
298 fid = AMD0F_PST_CTL_FID(p->st_cval);
299 vid = AMD0F_PST_CTL_VID(p->st_cval);
301 if (fid > fv_max.fid || fid < fv_min.fid) {
302 kprintf("cpu%d: Invalid FID %#x [%#x, %#x]\n",
303 mycpuid, fid, fv_min.fid, fv_max.fid);
306 if (vid < fv_max.vid || vid > fv_min.vid) {
307 kprintf("cpu%d: Invalid VID %#x [%#x, %#x]\n",
308 mycpuid, vid, fv_max.vid, fv_min.fid);
312 mvs = AMD0F_PST_CTL_MVS(p->st_cval);
313 rvo = AMD0F_PST_CTL_RVO(p->st_cval);
315 /* Only 0 is allowed, i.e. 25mV stepping */
317 kprintf("cpu%d: Invalid MVS %#x\n", mycpuid, mvs);
322 mvs_mv = 25 * (1 << mvs);
324 if (rvo_mv % mvs_mv != 0) {
325 kprintf("cpu%d: Invalid MVS/RVO (%#x/%#x)\n",
334 acpi_pst_amd0f_set_pstate(const struct acpi_pst_res *ctrl __unused,
335 const struct acpi_pst_res *status __unused,
336 const struct acpi_pstate *pstate)
338 struct amd0f_fidvid fv;
339 struct amd0f_xsit xsit;
341 fv.fid = AMD0F_PST_CTL_FID(pstate->st_cval);
342 fv.vid = AMD0F_PST_CTL_VID(pstate->st_cval);
344 xsit.rvo = AMD0F_PST_CTL_RVO(pstate->st_cval);
345 xsit.mvs = AMD0F_PST_CTL_MVS(pstate->st_cval);
346 xsit.vst = AMD0F_PST_CTL_VST(pstate->st_cval);
347 xsit.pll_time = AMD0F_PST_CTL_PLLTIME(pstate->st_cval);
348 xsit.irt = AMD0F_PST_CTL_IRT(pstate->st_cval);
350 return amd0f_set_fidvid(&fv, &xsit);
353 static const struct acpi_pstate *
354 acpi_pst_amd0f_get_pstate(const struct acpi_pst_res *status __unused,
355 const struct acpi_pstate *pstates, int npstates)
357 struct amd0f_fidvid fv;
360 error = amd0f_get_fidvid(&fv);
364 for (i = 0; i < npstates; ++i) {
365 const struct acpi_pstate *p = &pstates[i];
367 if (fv.fid == AMD0F_PST_ST_FID(p->st_sval) &&
368 fv.vid == AMD0F_PST_ST_VID(p->st_sval))
375 acpi_pst_amd_init(const struct acpi_pst_res *ctrl __unused,
376 const struct acpi_pst_res *status __unused)
381 static const struct acpi_pst_md *
382 acpi_pst_intel_probe(void)
386 if ((cpu_feature2 & CPUID2_EST) == 0)
389 family = cpu_id & 0xf00;
390 if (family != 0xf00 && family != 0x600)
392 return &acpi_pst_intel;
396 acpi_pst_intel_check_csr(const struct acpi_pst_res *ctrl,
397 const struct acpi_pst_res *status)
401 if (ctrl->pr_gas.SpaceId != status->pr_gas.SpaceId) {
402 kprintf("cpu%d: P-State control(%d)/status(%d) registers have "
403 "different SpaceId", mycpuid,
404 ctrl->pr_gas.SpaceId, status->pr_gas.SpaceId);
408 switch (ctrl->pr_gas.SpaceId) {
409 case ACPI_ADR_SPACE_FIXED_HARDWARE:
410 if (ctrl->pr_res != NULL || status->pr_res != NULL) {
411 /* XXX should panic() */
412 kprintf("cpu%d: Allocated resource for fixed hardware "
413 "registers\n", mycpuid);
418 case ACPI_ADR_SPACE_SYSTEM_IO:
419 if (ctrl->pr_res == NULL) {
420 kprintf("cpu%d: ioport allocation failed for control "
421 "register\n", mycpuid);
424 error = acpi_pst_md_gas_verify(&ctrl->pr_gas);
426 kprintf("cpu%d: Invalid control register GAS\n",
431 if (status->pr_res == NULL) {
432 kprintf("cpu%d: ioport allocation failed for status "
433 "register\n", mycpuid);
436 error = acpi_pst_md_gas_verify(&status->pr_gas);
438 kprintf("cpu%d: Invalid status register GAS\n",
445 kprintf("cpu%d: Invalid P-State control/status register "
446 "SpaceId %d\n", mycpuid, ctrl->pr_gas.SpaceId);
453 acpi_pst_intel_check_pstates(const struct acpi_pstate *pstates __unused,
454 int npstates __unused)
460 acpi_pst_intel_init(const struct acpi_pst_res *ctrl __unused,
461 const struct acpi_pst_res *status __unused)
463 uint32_t family, model;
464 uint64_t misc_enable;
466 family = cpu_id & 0xf00;
467 if (family == 0xf00) {
468 /* EST enable bit is reserved in INTEL_MSR_MISC_ENABLE */
471 KKASSERT(family == 0x600);
473 model = ((cpu_id & 0xf0000) >> 12) | ((cpu_id & 0xf0) >> 4);
475 /* EST enable bit is reserved in INTEL_MSR_MISC_ENABLE */
479 misc_enable = rdmsr(INTEL_MSR_MISC_ENABLE);
480 if ((misc_enable & INTEL_MSR_MISC_EST_EN) == 0) {
481 misc_enable |= INTEL_MSR_MISC_EST_EN;
482 wrmsr(INTEL_MSR_MISC_ENABLE, misc_enable);
484 misc_enable = rdmsr(INTEL_MSR_MISC_ENABLE);
485 if ((misc_enable & INTEL_MSR_MISC_EST_EN) == 0) {
486 kprintf("cpu%d: Can't enable EST\n", mycpuid);
494 acpi_pst_intel_set_pstate(const struct acpi_pst_res *ctrl,
495 const struct acpi_pst_res *status __unused,
496 const struct acpi_pstate *pstate)
498 if (ctrl->pr_res != NULL) {
499 acpi_pst_md_res_write(ctrl, pstate->st_cval);
503 ctl = rdmsr(INTEL_MSR_PERF_CTL);
504 ctl &= ~INTEL_MSR_PERF_MASK;
505 ctl |= (pstate->st_cval & INTEL_MSR_PERF_MASK);
506 wrmsr(INTEL_MSR_PERF_CTL, ctl);
511 static const struct acpi_pstate *
512 acpi_pst_intel_get_pstate(const struct acpi_pst_res *status,
513 const struct acpi_pstate *pstates, int npstates)
517 if (status->pr_res != NULL) {
520 st = acpi_pst_md_res_read(status);
521 for (i = 0; i < npstates; ++i) {
522 if (pstates[i].st_sval == st)
528 sval = rdmsr(INTEL_MSR_PERF_STATUS) & INTEL_MSR_PERF_MASK;
529 for (i = 0; i < npstates; ++i) {
530 if ((pstates[i].st_sval & INTEL_MSR_PERF_MASK) == sval)
538 acpi_pst_md_gas_asz(const ACPI_GENERIC_ADDRESS *gas)
542 if (gas->AccessWidth != 0)
543 asz = gas->AccessWidth;
545 asz = gas->BitWidth / NBBY;
559 acpi_pst_md_gas_verify(const ACPI_GENERIC_ADDRESS *gas)
563 if (gas->BitOffset % NBBY != 0)
566 end = gas->BitWidth / NBBY;
567 reg = gas->BitOffset / NBBY;
572 asz = acpi_pst_md_gas_asz(gas);
582 acpi_pst_md_res_read(const struct acpi_pst_res *res)
586 KKASSERT(res->pr_res != NULL);
587 asz = acpi_pst_md_gas_asz(&res->pr_gas);
588 reg = res->pr_gas.BitOffset / NBBY;
592 return bus_space_read_1(res->pr_bt, res->pr_bh, reg);
594 return bus_space_read_2(res->pr_bt, res->pr_bh, reg);
596 return bus_space_read_4(res->pr_bt, res->pr_bh, reg);
598 panic("unsupported access width %d\n", asz);
605 acpi_pst_md_res_write(const struct acpi_pst_res *res, uint32_t val)
609 KKASSERT(res->pr_res != NULL);
610 asz = acpi_pst_md_gas_asz(&res->pr_gas);
611 reg = res->pr_gas.BitOffset / NBBY;
615 bus_space_write_1(res->pr_bt, res->pr_bh, reg, val);
618 bus_space_write_2(res->pr_bt, res->pr_bh, reg, val);
621 bus_space_write_4(res->pr_bt, res->pr_bh, reg, val);
624 panic("unsupported access width %d\n", asz);