Deleted Added
full compact
acpi_throttle.c (142032) acpi_throttle.c (142203)
1/*-
2 * Copyright (c) 2003-2005 Nate Lawson (SDG)
3 * Copyright (c) 2001 Michael Smith
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28#include <sys/cdefs.h>
1/*-
2 * Copyright (c) 2003-2005 Nate Lawson (SDG)
3 * Copyright (c) 2001 Michael Smith
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28#include <sys/cdefs.h>
29__FBSDID("$FreeBSD: head/sys/dev/acpica/acpi_throttle.c 142032 2005-02-18 00:23:36Z njl $");
29__FBSDID("$FreeBSD: head/sys/dev/acpica/acpi_throttle.c 142203 2005-02-22 06:31:45Z njl $");
30
31#include "opt_acpi.h"
32#include <sys/param.h>
33#include <sys/bus.h>
34#include <sys/cpu.h>
35#include <sys/kernel.h>
36#include <sys/malloc.h>
37#include <sys/module.h>
38#include <sys/rman.h>
39
40#include <machine/bus.h>
41
42#include "acpi.h"
43#include <dev/acpica/acpivar.h>
44#include <dev/pci/pcivar.h>
45
46#include "cpufreq_if.h"
47
48/*
49 * Throttling provides relative frequency control. It involves modulating
50 * the clock so that the CPU is active for only a fraction of the normal
51 * clock cycle. It does not change voltage and so is less efficient than
52 * other mechanisms. Since it is relative, it can be used in addition to
53 * absolute cpufreq drivers. We support the ACPI 2.0 specification.
54 */
55
56struct acpi_throttle_softc {
57 device_t cpu_dev;
58 ACPI_HANDLE cpu_handle;
59 uint32_t cpu_p_blk; /* ACPI P_BLK location */
60 uint32_t cpu_p_blk_len; /* P_BLK length (must be 6). */
61 struct resource *cpu_p_cnt; /* Throttling control register */
62 int cpu_p_type; /* Resource type for cpu_p_cnt. */
63 uint32_t cpu_thr_state; /* Current throttle setting. */
64};
65
66#define THR_GET_REG(reg) \
67 (bus_space_read_4(rman_get_bustag((reg)), \
68 rman_get_bushandle((reg)), 0))
69#define THR_SET_REG(reg, val) \
70 (bus_space_write_4(rman_get_bustag((reg)), \
71 rman_get_bushandle((reg)), 0, (val)))
72
73/*
74 * Speeds are stored in counts, from 1 to CPU_MAX_SPEED, and
75 * reported to the user in hundredths of a percent.
76 */
77#define CPU_MAX_SPEED (1 << cpu_duty_width)
78#define CPU_SPEED_PERCENT(x) ((10000 * (x)) / CPU_MAX_SPEED)
79#define CPU_SPEED_PRINTABLE(x) (CPU_SPEED_PERCENT(x) / 10), \
80 (CPU_SPEED_PERCENT(x) % 10)
81#define CPU_P_CNT_THT_EN (1<<4)
82#define CPU_QUIRK_NO_THROTTLE (1<<1) /* Throttling is not usable. */
83
84#define PCI_VENDOR_INTEL 0x8086
85#define PCI_DEVICE_82371AB_3 0x7113 /* PIIX4 chipset for quirks. */
86#define PCI_REVISION_A_STEP 0
87#define PCI_REVISION_B_STEP 1
88
89static uint32_t cpu_duty_offset; /* Offset in P_CNT of throttle val. */
90static uint32_t cpu_duty_width; /* Bit width of throttle value. */
91static int thr_rid; /* Driver-wide resource id. */
92static int thr_quirks; /* Indicate any hardware bugs. */
93
94static void acpi_throttle_identify(driver_t *driver, device_t parent);
95static int acpi_throttle_probe(device_t dev);
96static int acpi_throttle_attach(device_t dev);
97static int acpi_throttle_evaluate(struct acpi_throttle_softc *sc);
98static int acpi_throttle_quirks(struct acpi_throttle_softc *sc);
99static int acpi_thr_settings(device_t dev, struct cf_setting *sets,
100 int *count);
101static int acpi_thr_set(device_t dev, const struct cf_setting *set);
102static int acpi_thr_get(device_t dev, struct cf_setting *set);
103static int acpi_thr_type(device_t dev, int *type);
104
105static device_method_t acpi_throttle_methods[] = {
106 /* Device interface */
107 DEVMETHOD(device_identify, acpi_throttle_identify),
108 DEVMETHOD(device_probe, acpi_throttle_probe),
109 DEVMETHOD(device_attach, acpi_throttle_attach),
110
111 /* cpufreq interface */
112 DEVMETHOD(cpufreq_drv_set, acpi_thr_set),
113 DEVMETHOD(cpufreq_drv_get, acpi_thr_get),
114 DEVMETHOD(cpufreq_drv_type, acpi_thr_type),
115 DEVMETHOD(cpufreq_drv_settings, acpi_thr_settings),
116 {0, 0}
117};
118
119static driver_t acpi_throttle_driver = {
120 "acpi_throttle",
121 acpi_throttle_methods,
122 sizeof(struct acpi_throttle_softc),
123};
124
125static devclass_t acpi_throttle_devclass;
126DRIVER_MODULE(acpi_throttle, cpu, acpi_throttle_driver, acpi_throttle_devclass,
127 0, 0);
128
129static void
130acpi_throttle_identify(driver_t *driver, device_t parent)
131{
132 ACPI_BUFFER buf;
133 ACPI_HANDLE handle;
134 ACPI_OBJECT *obj;
135
136 /* Make sure we're not being doubly invoked. */
137 if (device_find_child(parent, "acpi_throttle", -1) != NULL)
138 return;
139
140 /* Check for a valid duty width and parent CPU type. */
141 handle = acpi_get_handle(parent);
142 if (handle == NULL)
143 return;
144 if (AcpiGbl_FADT->DutyWidth == 0 ||
145 acpi_get_type(parent) != ACPI_TYPE_PROCESSOR)
146 return;
147
148 /*
149 * Add a child if there's a non-NULL P_BLK and correct length, or
150 * if the _PTC method is present.
151 */
152 buf.Pointer = NULL;
153 buf.Length = ACPI_ALLOCATE_BUFFER;
154 if (ACPI_FAILURE(AcpiEvaluateObject(handle, NULL, NULL, &buf)))
155 return;
156 obj = (ACPI_OBJECT *)buf.Pointer;
157 if ((obj->Processor.PblkAddress && obj->Processor.PblkLength >= 4) ||
158 ACPI_SUCCESS(AcpiEvaluateObject(handle, "_PTC", NULL, NULL))) {
159 if (BUS_ADD_CHILD(parent, 0, "acpi_throttle", -1) == NULL)
160 device_printf(parent, "add throttle child failed\n");
161 }
162 AcpiOsFree(obj);
163}
164
165static int
166acpi_throttle_probe(device_t dev)
167{
168
30
31#include "opt_acpi.h"
32#include <sys/param.h>
33#include <sys/bus.h>
34#include <sys/cpu.h>
35#include <sys/kernel.h>
36#include <sys/malloc.h>
37#include <sys/module.h>
38#include <sys/rman.h>
39
40#include <machine/bus.h>
41
42#include "acpi.h"
43#include <dev/acpica/acpivar.h>
44#include <dev/pci/pcivar.h>
45
46#include "cpufreq_if.h"
47
48/*
49 * Throttling provides relative frequency control. It involves modulating
50 * the clock so that the CPU is active for only a fraction of the normal
51 * clock cycle. It does not change voltage and so is less efficient than
52 * other mechanisms. Since it is relative, it can be used in addition to
53 * absolute cpufreq drivers. We support the ACPI 2.0 specification.
54 */
55
56struct acpi_throttle_softc {
57 device_t cpu_dev;
58 ACPI_HANDLE cpu_handle;
59 uint32_t cpu_p_blk; /* ACPI P_BLK location */
60 uint32_t cpu_p_blk_len; /* P_BLK length (must be 6). */
61 struct resource *cpu_p_cnt; /* Throttling control register */
62 int cpu_p_type; /* Resource type for cpu_p_cnt. */
63 uint32_t cpu_thr_state; /* Current throttle setting. */
64};
65
66#define THR_GET_REG(reg) \
67 (bus_space_read_4(rman_get_bustag((reg)), \
68 rman_get_bushandle((reg)), 0))
69#define THR_SET_REG(reg, val) \
70 (bus_space_write_4(rman_get_bustag((reg)), \
71 rman_get_bushandle((reg)), 0, (val)))
72
73/*
74 * Speeds are stored in counts, from 1 to CPU_MAX_SPEED, and
75 * reported to the user in hundredths of a percent.
76 */
77#define CPU_MAX_SPEED (1 << cpu_duty_width)
78#define CPU_SPEED_PERCENT(x) ((10000 * (x)) / CPU_MAX_SPEED)
79#define CPU_SPEED_PRINTABLE(x) (CPU_SPEED_PERCENT(x) / 10), \
80 (CPU_SPEED_PERCENT(x) % 10)
81#define CPU_P_CNT_THT_EN (1<<4)
82#define CPU_QUIRK_NO_THROTTLE (1<<1) /* Throttling is not usable. */
83
84#define PCI_VENDOR_INTEL 0x8086
85#define PCI_DEVICE_82371AB_3 0x7113 /* PIIX4 chipset for quirks. */
86#define PCI_REVISION_A_STEP 0
87#define PCI_REVISION_B_STEP 1
88
89static uint32_t cpu_duty_offset; /* Offset in P_CNT of throttle val. */
90static uint32_t cpu_duty_width; /* Bit width of throttle value. */
91static int thr_rid; /* Driver-wide resource id. */
92static int thr_quirks; /* Indicate any hardware bugs. */
93
94static void acpi_throttle_identify(driver_t *driver, device_t parent);
95static int acpi_throttle_probe(device_t dev);
96static int acpi_throttle_attach(device_t dev);
97static int acpi_throttle_evaluate(struct acpi_throttle_softc *sc);
98static int acpi_throttle_quirks(struct acpi_throttle_softc *sc);
99static int acpi_thr_settings(device_t dev, struct cf_setting *sets,
100 int *count);
101static int acpi_thr_set(device_t dev, const struct cf_setting *set);
102static int acpi_thr_get(device_t dev, struct cf_setting *set);
103static int acpi_thr_type(device_t dev, int *type);
104
105static device_method_t acpi_throttle_methods[] = {
106 /* Device interface */
107 DEVMETHOD(device_identify, acpi_throttle_identify),
108 DEVMETHOD(device_probe, acpi_throttle_probe),
109 DEVMETHOD(device_attach, acpi_throttle_attach),
110
111 /* cpufreq interface */
112 DEVMETHOD(cpufreq_drv_set, acpi_thr_set),
113 DEVMETHOD(cpufreq_drv_get, acpi_thr_get),
114 DEVMETHOD(cpufreq_drv_type, acpi_thr_type),
115 DEVMETHOD(cpufreq_drv_settings, acpi_thr_settings),
116 {0, 0}
117};
118
119static driver_t acpi_throttle_driver = {
120 "acpi_throttle",
121 acpi_throttle_methods,
122 sizeof(struct acpi_throttle_softc),
123};
124
125static devclass_t acpi_throttle_devclass;
126DRIVER_MODULE(acpi_throttle, cpu, acpi_throttle_driver, acpi_throttle_devclass,
127 0, 0);
128
129static void
130acpi_throttle_identify(driver_t *driver, device_t parent)
131{
132 ACPI_BUFFER buf;
133 ACPI_HANDLE handle;
134 ACPI_OBJECT *obj;
135
136 /* Make sure we're not being doubly invoked. */
137 if (device_find_child(parent, "acpi_throttle", -1) != NULL)
138 return;
139
140 /* Check for a valid duty width and parent CPU type. */
141 handle = acpi_get_handle(parent);
142 if (handle == NULL)
143 return;
144 if (AcpiGbl_FADT->DutyWidth == 0 ||
145 acpi_get_type(parent) != ACPI_TYPE_PROCESSOR)
146 return;
147
148 /*
149 * Add a child if there's a non-NULL P_BLK and correct length, or
150 * if the _PTC method is present.
151 */
152 buf.Pointer = NULL;
153 buf.Length = ACPI_ALLOCATE_BUFFER;
154 if (ACPI_FAILURE(AcpiEvaluateObject(handle, NULL, NULL, &buf)))
155 return;
156 obj = (ACPI_OBJECT *)buf.Pointer;
157 if ((obj->Processor.PblkAddress && obj->Processor.PblkLength >= 4) ||
158 ACPI_SUCCESS(AcpiEvaluateObject(handle, "_PTC", NULL, NULL))) {
159 if (BUS_ADD_CHILD(parent, 0, "acpi_throttle", -1) == NULL)
160 device_printf(parent, "add throttle child failed\n");
161 }
162 AcpiOsFree(obj);
163}
164
165static int
166acpi_throttle_probe(device_t dev)
167{
168
169 if (resource_disabled("acpi_throttle", 0))
170 return (ENXIO);
171
169 device_set_desc(dev, "ACPI CPU Throttling");
170 return (0);
171}
172
173static int
174acpi_throttle_attach(device_t dev)
175{
176 struct acpi_throttle_softc *sc;
177 ACPI_BUFFER buf;
178 ACPI_OBJECT *obj;
179 ACPI_STATUS status;
180 int error;
181
182 sc = device_get_softc(dev);
183 sc->cpu_dev = dev;
184 sc->cpu_handle = acpi_get_handle(dev);
185
186 buf.Pointer = NULL;
187 buf.Length = ACPI_ALLOCATE_BUFFER;
188 status = AcpiEvaluateObject(sc->cpu_handle, NULL, NULL, &buf);
189 if (ACPI_FAILURE(status)) {
190 device_printf(dev, "attach failed to get Processor obj - %s\n",
191 AcpiFormatException(status));
192 return (ENXIO);
193 }
194 obj = (ACPI_OBJECT *)buf.Pointer;
195 sc->cpu_p_blk = obj->Processor.PblkAddress;
196 sc->cpu_p_blk_len = obj->Processor.PblkLength;
197 AcpiOsFree(obj);
198
199 /* If this is the first device probed, check for quirks. */
200 if (device_get_unit(dev) == 0)
201 acpi_throttle_quirks(sc);
202
203 /* Attempt to attach the actual throttling register. */
204 error = acpi_throttle_evaluate(sc);
205 if (error)
206 return (error);
207
208 /* Everything went ok, register with cpufreq(4). */
209 cpufreq_register(dev);
210 return (0);
211}
212
213static int
214acpi_throttle_evaluate(struct acpi_throttle_softc *sc)
215{
216 uint32_t duty_end;
217 ACPI_BUFFER buf;
218 ACPI_OBJECT obj;
219 ACPI_GENERIC_ADDRESS gas;
220 ACPI_STATUS status;
221
222 /* Get throttling parameters from the FADT. 0 means not supported. */
223 if (device_get_unit(sc->cpu_dev) == 0) {
224 cpu_duty_offset = AcpiGbl_FADT->DutyOffset;
225 cpu_duty_width = AcpiGbl_FADT->DutyWidth;
226 }
227 if (cpu_duty_width == 0 || (thr_quirks & CPU_QUIRK_NO_THROTTLE) != 0)
228 return (ENXIO);
229
230 /* Validate the duty offset/width. */
231 duty_end = cpu_duty_offset + cpu_duty_width - 1;
232 if (duty_end > 31) {
233 device_printf(sc->cpu_dev,
234 "CLK_VAL field overflows P_CNT register\n");
235 return (ENXIO);
236 }
237 if (cpu_duty_offset <= 4 && duty_end >= 4) {
238 device_printf(sc->cpu_dev,
239 "CLK_VAL field overlaps THT_EN bit\n");
240 return (ENXIO);
241 }
242
243 /*
244 * If not present, fall back to using the processor's P_BLK to find
245 * the P_CNT register.
246 *
247 * Note that some systems seem to duplicate the P_BLK pointer
248 * across multiple CPUs, so not getting the resource is not fatal.
249 */
250 buf.Pointer = &obj;
251 buf.Length = sizeof(obj);
252 status = AcpiEvaluateObject(sc->cpu_handle, "_PTC", NULL, &buf);
253 if (ACPI_SUCCESS(status)) {
254 if (obj.Buffer.Length < sizeof(ACPI_GENERIC_ADDRESS) + 3) {
255 device_printf(sc->cpu_dev, "_PTC buffer too small\n");
256 return (ENXIO);
257 }
258 memcpy(&gas, obj.Buffer.Pointer + 3, sizeof(gas));
259 acpi_bus_alloc_gas(sc->cpu_dev, &sc->cpu_p_type, &thr_rid,
260 &gas, &sc->cpu_p_cnt);
261 if (sc->cpu_p_cnt != NULL && bootverbose) {
262 device_printf(sc->cpu_dev, "P_CNT from _PTC %#jx\n",
263 gas.Address);
264 }
265 }
266
267 /* If _PTC not present or other failure, try the P_BLK. */
268 if (sc->cpu_p_cnt == NULL) {
269 /*
270 * The spec says P_BLK must be 6 bytes long. However, some
271 * systems use it to indicate a fractional set of features
272 * present so we take anything >= 4.
273 */
274 if (sc->cpu_p_blk_len < 4)
275 return (ENXIO);
276 gas.Address = sc->cpu_p_blk;
277 gas.AddressSpaceId = ACPI_ADR_SPACE_SYSTEM_IO;
278 gas.RegisterBitWidth = 32;
279 acpi_bus_alloc_gas(sc->cpu_dev, &sc->cpu_p_type, &thr_rid,
280 &gas, &sc->cpu_p_cnt);
281 if (sc->cpu_p_cnt != NULL) {
282 if (bootverbose)
283 device_printf(sc->cpu_dev,
284 "P_CNT from P_BLK %#x\n", sc->cpu_p_blk);
285 } else {
286 device_printf(sc->cpu_dev, "failed to attach P_CNT\n");
287 return (ENXIO);
288 }
289 }
290 thr_rid++;
291
292 return (0);
293}
294
295static int
296acpi_throttle_quirks(struct acpi_throttle_softc *sc)
297{
298 device_t acpi_dev;
299
300 /* Look for various quirks of the PIIX4 part. */
301 acpi_dev = pci_find_device(PCI_VENDOR_INTEL, PCI_DEVICE_82371AB_3);
302 if (acpi_dev) {
303 switch (pci_get_revid(acpi_dev)) {
304 /*
305 * Disable throttling control on PIIX4 A and B-step.
306 * See specification changes #13 ("Manual Throttle Duty Cycle")
307 * and #14 ("Enabling and Disabling Manual Throttle"), plus
308 * erratum #5 ("STPCLK# Deassertion Time") from the January
309 * 2002 PIIX4 specification update. Note that few (if any)
310 * mobile systems ever used this part.
311 */
312 case PCI_REVISION_A_STEP:
313 case PCI_REVISION_B_STEP:
314 thr_quirks |= CPU_QUIRK_NO_THROTTLE;
315 break;
316 default:
317 break;
318 }
319 }
320
321 return (0);
322}
323
324static int
325acpi_thr_settings(device_t dev, struct cf_setting *sets, int *count)
326{
327 struct acpi_throttle_softc *sc;
328 int i, speed;
329
330 sc = device_get_softc(dev);
331 if (sets == NULL || count == NULL)
332 return (EINVAL);
333 if (*count < CPU_MAX_SPEED)
334 return (E2BIG);
335
336 /* Return a list of valid settings for this driver. */
337 memset(sets, CPUFREQ_VAL_UNKNOWN, sizeof(*sets) * CPU_MAX_SPEED);
338 for (i = 0, speed = CPU_MAX_SPEED; speed != 0; i++, speed--) {
339 sets[i].freq = CPU_SPEED_PERCENT(speed);
340 sets[i].dev = dev;
341 }
342 *count = CPU_MAX_SPEED;
343
344 return (0);
345}
346
347static int
348acpi_thr_set(device_t dev, const struct cf_setting *set)
349{
350 struct acpi_throttle_softc *sc;
351 uint32_t clk_val, p_cnt, speed;
352
353 if (set == NULL)
354 return (EINVAL);
355 sc = device_get_softc(dev);
356
357 /*
358 * Validate requested state converts to a duty cycle that is an
359 * integer from [1 .. CPU_MAX_SPEED].
360 */
361 speed = set->freq * CPU_MAX_SPEED / 10000;
362 if (speed * 10000 != set->freq * CPU_MAX_SPEED ||
363 speed < 1 || speed > CPU_MAX_SPEED)
364 return (EINVAL);
365
366 /* If we're at this setting, don't bother applying it again. */
367 if (speed == sc->cpu_thr_state)
368 return (0);
369
370 /* Get the current P_CNT value and disable throttling */
371 p_cnt = THR_GET_REG(sc->cpu_p_cnt);
372 p_cnt &= ~CPU_P_CNT_THT_EN;
373 THR_SET_REG(sc->cpu_p_cnt, p_cnt);
374
375 /* If we're at maximum speed, that's all */
376 if (speed < CPU_MAX_SPEED) {
377 /* Mask the old CLK_VAL off and OR in the new value */
378 clk_val = (CPU_MAX_SPEED - 1) << cpu_duty_offset;
379 p_cnt &= ~clk_val;
380 p_cnt |= (speed << cpu_duty_offset);
381
382 /* Write the new P_CNT value and then enable throttling */
383 THR_SET_REG(sc->cpu_p_cnt, p_cnt);
384 p_cnt |= CPU_P_CNT_THT_EN;
385 THR_SET_REG(sc->cpu_p_cnt, p_cnt);
386 }
387 sc->cpu_thr_state = speed;
388
389 return (0);
390}
391
392static int
393acpi_thr_get(device_t dev, struct cf_setting *set)
394{
395 struct acpi_throttle_softc *sc;
396 uint32_t p_cnt, clk_val;
397
398 if (set == NULL)
399 return (EINVAL);
400 sc = device_get_softc(dev);
401
402 /* Get the current throttling setting from P_CNT. */
403 p_cnt = THR_GET_REG(sc->cpu_p_cnt);
404 clk_val = (p_cnt >> cpu_duty_offset) & (CPU_MAX_SPEED - 1);
405 sc->cpu_thr_state = clk_val;
406
407 memset(set, CPUFREQ_VAL_UNKNOWN, sizeof(*set));
408 set->freq = CPU_SPEED_PERCENT(clk_val);
409 set->dev = dev;
410
411 return (0);
412}
413
414static int
415acpi_thr_type(device_t dev, int *type)
416{
417
418 if (type == NULL)
419 return (EINVAL);
420
421 *type = CPUFREQ_TYPE_RELATIVE;
422 return (0);
423}
172 device_set_desc(dev, "ACPI CPU Throttling");
173 return (0);
174}
175
176static int
177acpi_throttle_attach(device_t dev)
178{
179 struct acpi_throttle_softc *sc;
180 ACPI_BUFFER buf;
181 ACPI_OBJECT *obj;
182 ACPI_STATUS status;
183 int error;
184
185 sc = device_get_softc(dev);
186 sc->cpu_dev = dev;
187 sc->cpu_handle = acpi_get_handle(dev);
188
189 buf.Pointer = NULL;
190 buf.Length = ACPI_ALLOCATE_BUFFER;
191 status = AcpiEvaluateObject(sc->cpu_handle, NULL, NULL, &buf);
192 if (ACPI_FAILURE(status)) {
193 device_printf(dev, "attach failed to get Processor obj - %s\n",
194 AcpiFormatException(status));
195 return (ENXIO);
196 }
197 obj = (ACPI_OBJECT *)buf.Pointer;
198 sc->cpu_p_blk = obj->Processor.PblkAddress;
199 sc->cpu_p_blk_len = obj->Processor.PblkLength;
200 AcpiOsFree(obj);
201
202 /* If this is the first device probed, check for quirks. */
203 if (device_get_unit(dev) == 0)
204 acpi_throttle_quirks(sc);
205
206 /* Attempt to attach the actual throttling register. */
207 error = acpi_throttle_evaluate(sc);
208 if (error)
209 return (error);
210
211 /* Everything went ok, register with cpufreq(4). */
212 cpufreq_register(dev);
213 return (0);
214}
215
216static int
217acpi_throttle_evaluate(struct acpi_throttle_softc *sc)
218{
219 uint32_t duty_end;
220 ACPI_BUFFER buf;
221 ACPI_OBJECT obj;
222 ACPI_GENERIC_ADDRESS gas;
223 ACPI_STATUS status;
224
225 /* Get throttling parameters from the FADT. 0 means not supported. */
226 if (device_get_unit(sc->cpu_dev) == 0) {
227 cpu_duty_offset = AcpiGbl_FADT->DutyOffset;
228 cpu_duty_width = AcpiGbl_FADT->DutyWidth;
229 }
230 if (cpu_duty_width == 0 || (thr_quirks & CPU_QUIRK_NO_THROTTLE) != 0)
231 return (ENXIO);
232
233 /* Validate the duty offset/width. */
234 duty_end = cpu_duty_offset + cpu_duty_width - 1;
235 if (duty_end > 31) {
236 device_printf(sc->cpu_dev,
237 "CLK_VAL field overflows P_CNT register\n");
238 return (ENXIO);
239 }
240 if (cpu_duty_offset <= 4 && duty_end >= 4) {
241 device_printf(sc->cpu_dev,
242 "CLK_VAL field overlaps THT_EN bit\n");
243 return (ENXIO);
244 }
245
246 /*
247 * If not present, fall back to using the processor's P_BLK to find
248 * the P_CNT register.
249 *
250 * Note that some systems seem to duplicate the P_BLK pointer
251 * across multiple CPUs, so not getting the resource is not fatal.
252 */
253 buf.Pointer = &obj;
254 buf.Length = sizeof(obj);
255 status = AcpiEvaluateObject(sc->cpu_handle, "_PTC", NULL, &buf);
256 if (ACPI_SUCCESS(status)) {
257 if (obj.Buffer.Length < sizeof(ACPI_GENERIC_ADDRESS) + 3) {
258 device_printf(sc->cpu_dev, "_PTC buffer too small\n");
259 return (ENXIO);
260 }
261 memcpy(&gas, obj.Buffer.Pointer + 3, sizeof(gas));
262 acpi_bus_alloc_gas(sc->cpu_dev, &sc->cpu_p_type, &thr_rid,
263 &gas, &sc->cpu_p_cnt);
264 if (sc->cpu_p_cnt != NULL && bootverbose) {
265 device_printf(sc->cpu_dev, "P_CNT from _PTC %#jx\n",
266 gas.Address);
267 }
268 }
269
270 /* If _PTC not present or other failure, try the P_BLK. */
271 if (sc->cpu_p_cnt == NULL) {
272 /*
273 * The spec says P_BLK must be 6 bytes long. However, some
274 * systems use it to indicate a fractional set of features
275 * present so we take anything >= 4.
276 */
277 if (sc->cpu_p_blk_len < 4)
278 return (ENXIO);
279 gas.Address = sc->cpu_p_blk;
280 gas.AddressSpaceId = ACPI_ADR_SPACE_SYSTEM_IO;
281 gas.RegisterBitWidth = 32;
282 acpi_bus_alloc_gas(sc->cpu_dev, &sc->cpu_p_type, &thr_rid,
283 &gas, &sc->cpu_p_cnt);
284 if (sc->cpu_p_cnt != NULL) {
285 if (bootverbose)
286 device_printf(sc->cpu_dev,
287 "P_CNT from P_BLK %#x\n", sc->cpu_p_blk);
288 } else {
289 device_printf(sc->cpu_dev, "failed to attach P_CNT\n");
290 return (ENXIO);
291 }
292 }
293 thr_rid++;
294
295 return (0);
296}
297
298static int
299acpi_throttle_quirks(struct acpi_throttle_softc *sc)
300{
301 device_t acpi_dev;
302
303 /* Look for various quirks of the PIIX4 part. */
304 acpi_dev = pci_find_device(PCI_VENDOR_INTEL, PCI_DEVICE_82371AB_3);
305 if (acpi_dev) {
306 switch (pci_get_revid(acpi_dev)) {
307 /*
308 * Disable throttling control on PIIX4 A and B-step.
309 * See specification changes #13 ("Manual Throttle Duty Cycle")
310 * and #14 ("Enabling and Disabling Manual Throttle"), plus
311 * erratum #5 ("STPCLK# Deassertion Time") from the January
312 * 2002 PIIX4 specification update. Note that few (if any)
313 * mobile systems ever used this part.
314 */
315 case PCI_REVISION_A_STEP:
316 case PCI_REVISION_B_STEP:
317 thr_quirks |= CPU_QUIRK_NO_THROTTLE;
318 break;
319 default:
320 break;
321 }
322 }
323
324 return (0);
325}
326
327static int
328acpi_thr_settings(device_t dev, struct cf_setting *sets, int *count)
329{
330 struct acpi_throttle_softc *sc;
331 int i, speed;
332
333 sc = device_get_softc(dev);
334 if (sets == NULL || count == NULL)
335 return (EINVAL);
336 if (*count < CPU_MAX_SPEED)
337 return (E2BIG);
338
339 /* Return a list of valid settings for this driver. */
340 memset(sets, CPUFREQ_VAL_UNKNOWN, sizeof(*sets) * CPU_MAX_SPEED);
341 for (i = 0, speed = CPU_MAX_SPEED; speed != 0; i++, speed--) {
342 sets[i].freq = CPU_SPEED_PERCENT(speed);
343 sets[i].dev = dev;
344 }
345 *count = CPU_MAX_SPEED;
346
347 return (0);
348}
349
350static int
351acpi_thr_set(device_t dev, const struct cf_setting *set)
352{
353 struct acpi_throttle_softc *sc;
354 uint32_t clk_val, p_cnt, speed;
355
356 if (set == NULL)
357 return (EINVAL);
358 sc = device_get_softc(dev);
359
360 /*
361 * Validate requested state converts to a duty cycle that is an
362 * integer from [1 .. CPU_MAX_SPEED].
363 */
364 speed = set->freq * CPU_MAX_SPEED / 10000;
365 if (speed * 10000 != set->freq * CPU_MAX_SPEED ||
366 speed < 1 || speed > CPU_MAX_SPEED)
367 return (EINVAL);
368
369 /* If we're at this setting, don't bother applying it again. */
370 if (speed == sc->cpu_thr_state)
371 return (0);
372
373 /* Get the current P_CNT value and disable throttling */
374 p_cnt = THR_GET_REG(sc->cpu_p_cnt);
375 p_cnt &= ~CPU_P_CNT_THT_EN;
376 THR_SET_REG(sc->cpu_p_cnt, p_cnt);
377
378 /* If we're at maximum speed, that's all */
379 if (speed < CPU_MAX_SPEED) {
380 /* Mask the old CLK_VAL off and OR in the new value */
381 clk_val = (CPU_MAX_SPEED - 1) << cpu_duty_offset;
382 p_cnt &= ~clk_val;
383 p_cnt |= (speed << cpu_duty_offset);
384
385 /* Write the new P_CNT value and then enable throttling */
386 THR_SET_REG(sc->cpu_p_cnt, p_cnt);
387 p_cnt |= CPU_P_CNT_THT_EN;
388 THR_SET_REG(sc->cpu_p_cnt, p_cnt);
389 }
390 sc->cpu_thr_state = speed;
391
392 return (0);
393}
394
395static int
396acpi_thr_get(device_t dev, struct cf_setting *set)
397{
398 struct acpi_throttle_softc *sc;
399 uint32_t p_cnt, clk_val;
400
401 if (set == NULL)
402 return (EINVAL);
403 sc = device_get_softc(dev);
404
405 /* Get the current throttling setting from P_CNT. */
406 p_cnt = THR_GET_REG(sc->cpu_p_cnt);
407 clk_val = (p_cnt >> cpu_duty_offset) & (CPU_MAX_SPEED - 1);
408 sc->cpu_thr_state = clk_val;
409
410 memset(set, CPUFREQ_VAL_UNKNOWN, sizeof(*set));
411 set->freq = CPU_SPEED_PERCENT(clk_val);
412 set->dev = dev;
413
414 return (0);
415}
416
417static int
418acpi_thr_type(device_t dev, int *type)
419{
420
421 if (type == NULL)
422 return (EINVAL);
423
424 *type = CPUFREQ_TYPE_RELATIVE;
425 return (0);
426}