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>
38 #include <machine/md_var.h>
41 #include "acpi_cpu_pstate.h"
43 #define AMD_APMI_HWPSTATE 0x80
45 #define AMD_MSR_PSTATE_CSR_MASK 0x7ULL
46 #define AMD1XH_MSR_PSTATE_CTL 0xc0010062
47 #define AMD1XH_MSR_PSTATE_ST 0xc0010063
49 #define AMD_MSR_PSTATE_EN 0x8000000000000000ULL
51 #define AMD10H_MSR_PSTATE_START 0xc0010064
52 #define AMD10H_MSR_PSTATE_COUNT 5
54 static const struct acpi_pst_md *
55 acpi_pst_amd_probe(void);
56 static int acpi_pst_amd_check_csr(const ACPI_RESOURCE_GENERIC_REGISTER *,
57 const ACPI_RESOURCE_GENERIC_REGISTER *);
58 static int acpi_pst_amd1xh_check_pstates(const struct acpi_pstate *, int,
60 static int acpi_pst_amd10h_check_pstates(const struct acpi_pstate *, int);
61 static int acpi_pst_amd1xh_set_pstate(
62 const ACPI_RESOURCE_GENERIC_REGISTER *,
63 const ACPI_RESOURCE_GENERIC_REGISTER *,
64 const struct acpi_pstate *);
65 static const struct acpi_pstate *
66 acpi_pst_amd1xh_get_pstate(
67 const ACPI_RESOURCE_GENERIC_REGISTER *,
68 const struct acpi_pstate *, int);
70 static const struct acpi_pst_md acpi_pst_amd10h = {
71 .pmd_check_csr = acpi_pst_amd_check_csr,
72 .pmd_check_pstates = acpi_pst_amd10h_check_pstates,
73 .pmd_set_pstate = acpi_pst_amd1xh_set_pstate,
74 .pmd_get_pstate = acpi_pst_amd1xh_get_pstate
77 const struct acpi_pst_md *
78 acpi_pst_md_probe(void)
80 if (strcmp(cpu_vendor, "AuthenticAMD") == 0)
81 return acpi_pst_amd_probe();
85 static const struct acpi_pst_md *
86 acpi_pst_amd_probe(void)
88 uint32_t regs[4], ext_family;
90 if ((cpu_id & 0x00000f00) != 0x00000f00)
93 /* Check whether APMI exists */
94 do_cpuid(0x80000000, regs);
95 if (regs[0] < 0x80000007)
99 do_cpuid(0x80000007, regs);
101 ext_family = cpu_id & 0x0ff00000;
102 switch (ext_family) {
103 case 0x00100000: /* Family 10h */
105 return &acpi_pst_amd10h;
115 acpi_pst_amd_check_csr(const ACPI_RESOURCE_GENERIC_REGISTER *ctrl,
116 const ACPI_RESOURCE_GENERIC_REGISTER *status)
118 if (ctrl->SpaceId != ACPI_ADR_SPACE_FIXED_HARDWARE) {
119 kprintf("cpu%d: Invalid P-State control register\n", mycpuid);
122 if (status->SpaceId != ACPI_ADR_SPACE_FIXED_HARDWARE) {
123 kprintf("cpu%d: Invalid P-State status register\n", mycpuid);
130 acpi_pst_amd1xh_check_pstates(const struct acpi_pstate *pstates, int npstates,
131 uint32_t msr_start, uint32_t msr_end)
136 * Make sure that related MSR P-State registers are enabled.
139 * We don't check status register value here;
140 * it will not be used.
142 for (i = 0; i < npstates; ++i) {
147 (pstates[i].st_cval & AMD_MSR_PSTATE_CSR_MASK);
148 if (msr >= msr_end) {
149 kprintf("cpu%d: MSR P-State register %#08x "
150 "does not exist\n", mycpuid, msr);
155 if ((pstate & AMD_MSR_PSTATE_EN) == 0) {
156 kprintf("cpu%d: MSR P-State register %#08x "
157 "is not enabled\n", mycpuid, msr);
165 acpi_pst_amd10h_check_pstates(const struct acpi_pstate *pstates, int npstates)
167 /* Only P0-P4 are supported */
168 if (npstates > AMD10H_MSR_PSTATE_COUNT) {
169 kprintf("cpu%d: only P0-P4 is allowed\n", mycpuid);
173 return acpi_pst_amd1xh_check_pstates(pstates, npstates,
174 AMD10H_MSR_PSTATE_START,
175 AMD10H_MSR_PSTATE_START + AMD10H_MSR_PSTATE_COUNT);
179 acpi_pst_amd1xh_set_pstate(const ACPI_RESOURCE_GENERIC_REGISTER *ctrl __unused,
180 const ACPI_RESOURCE_GENERIC_REGISTER *status __unused,
181 const struct acpi_pstate *pstate)
185 cval = pstate->st_cval & AMD_MSR_PSTATE_CSR_MASK;
186 wrmsr(AMD1XH_MSR_PSTATE_CTL, cval);
189 * Don't check AMD1XH_MSR_PSTATE_ST here, since it is
190 * affected by various P-State limits.
193 * AMD Family 10h Processor BKDG Rev 3.20 (#31116)
194 * 2.4.2.4 P-state Transition Behavior
200 static const struct acpi_pstate *
201 acpi_pst_amd1xh_get_pstate(
202 const ACPI_RESOURCE_GENERIC_REGISTER *status __unused,
203 const struct acpi_pstate *pstates, int npstates)
208 sval = rdmsr(AMD1XH_MSR_PSTATE_ST) & AMD_MSR_PSTATE_CSR_MASK;
209 for (i = 0; i < npstates; ++i) {
210 if ((pstates[i].st_sval & AMD_MSR_PSTATE_CSR_MASK) == sval)