xref: /freebsd/sys/dev/acpica/acpi_throttle.c (revision 6b806d21d144c25f4fad714e1c0cf780f5e27d7e)
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$");
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 
56 struct 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 };
64 
65 #define THR_GET_REG(reg) 					\
66 	(bus_space_read_4(rman_get_bustag((reg)), 		\
67 			  rman_get_bushandle((reg)), 0))
68 #define THR_SET_REG(reg, val)					\
69 	(bus_space_write_4(rman_get_bustag((reg)), 		\
70 			   rman_get_bushandle((reg)), 0, (val)))
71 
72 /*
73  * Speeds are stored in counts, from 1 to CPU_MAX_SPEED, and
74  * reported to the user in hundredths of a percent.
75  */
76 #define CPU_MAX_SPEED		(1 << cpu_duty_width)
77 #define CPU_SPEED_PERCENT(x)	((10000 * (x)) / CPU_MAX_SPEED)
78 #define CPU_SPEED_PRINTABLE(x)	(CPU_SPEED_PERCENT(x) / 10),	\
79 				(CPU_SPEED_PERCENT(x) % 10)
80 #define CPU_P_CNT_THT_EN	(1<<4)
81 #define CPU_QUIRK_NO_THROTTLE	(1<<1)	/* Throttling is not usable. */
82 
83 #define PCI_VENDOR_INTEL	0x8086
84 #define PCI_DEVICE_82371AB_3	0x7113	/* PIIX4 chipset for quirks. */
85 #define PCI_REVISION_A_STEP	0
86 #define PCI_REVISION_B_STEP	1
87 
88 static uint32_t	cpu_duty_offset;	/* Offset in P_CNT of throttle val. */
89 static uint32_t	cpu_duty_width;		/* Bit width of throttle value. */
90 static uint32_t	cpu_throttle_state;	/* Current throttle setting. */
91 static int	thr_rid;		/* Driver-wide resource id. */
92 static int	thr_quirks;		/* Indicate any hardware bugs. */
93 
94 static void	acpi_throttle_identify(driver_t *driver, device_t parent);
95 static int	acpi_throttle_probe(device_t dev);
96 static int	acpi_throttle_attach(device_t dev);
97 static int	acpi_throttle_evaluate(struct acpi_throttle_softc *sc);
98 static int	acpi_throttle_quirks(struct acpi_throttle_softc *sc);
99 static int	acpi_thr_settings(device_t dev, struct cf_setting *sets,
100 		    int *count, int *type);
101 static int	acpi_thr_set(device_t dev, const struct cf_setting *set);
102 static int	acpi_thr_get(device_t dev, struct cf_setting *set);
103 
104 static device_method_t acpi_throttle_methods[] = {
105 	/* Device interface */
106 	DEVMETHOD(device_identify,	acpi_throttle_identify),
107 	DEVMETHOD(device_probe,		acpi_throttle_probe),
108 	DEVMETHOD(device_attach,	acpi_throttle_attach),
109 
110 	/* cpufreq interface */
111 	DEVMETHOD(cpufreq_drv_set,	acpi_thr_set),
112 	DEVMETHOD(cpufreq_drv_get,	acpi_thr_get),
113 	DEVMETHOD(cpufreq_drv_settings,	acpi_thr_settings),
114 	{0, 0}
115 };
116 
117 static driver_t acpi_throttle_driver = {
118 	"acpi_throttle",
119 	acpi_throttle_methods,
120 	sizeof(struct acpi_throttle_softc),
121 };
122 
123 static devclass_t acpi_throttle_devclass;
124 DRIVER_MODULE(acpi_throttle, cpu, acpi_throttle_driver, acpi_throttle_devclass,
125     0, 0);
126 
127 static void
128 acpi_throttle_identify(driver_t *driver, device_t parent)
129 {
130 
131 	/* Make sure we're not being doubly invoked. */
132 	if (device_find_child(parent, "acpi_throttle", 0) != NULL)
133 		return;
134 
135 	/* Check for a valid duty width and parent CPU type. */
136 	if (acpi_get_handle(parent) == NULL)
137 		return;
138 	if (AcpiGbl_FADT->DutyWidth == 0 ||
139 	    acpi_get_type(parent) != ACPI_TYPE_PROCESSOR)
140 		return;
141 	if (BUS_ADD_CHILD(parent, 0, "acpi_throttle", 0) == NULL)
142 		device_printf(parent, "acpi_throttle: add child failed\n");
143 }
144 
145 static int
146 acpi_throttle_probe(device_t dev)
147 {
148 
149 	device_set_desc(dev, "ACPI CPU Throttling");
150 	return (0);
151 }
152 
153 static int
154 acpi_throttle_attach(device_t dev)
155 {
156 	struct acpi_throttle_softc *sc;
157 	ACPI_BUFFER buf;
158 	ACPI_OBJECT*obj;
159 	ACPI_STATUS status;
160 
161 	sc = device_get_softc(dev);
162 	sc->cpu_dev = dev;
163 	sc->cpu_handle = acpi_get_handle(dev);
164 
165 	buf.Pointer = NULL;
166 	buf.Length = ACPI_ALLOCATE_BUFFER;
167 	status = AcpiEvaluateObject(sc->cpu_handle, NULL, NULL, &buf);
168 	if (ACPI_FAILURE(status)) {
169 		device_printf(dev, "attach failed to get Processor obj - %s\n",
170 		    AcpiFormatException(status));
171 		return (ENXIO);
172 	}
173 	obj = (ACPI_OBJECT *)buf.Pointer;
174 	sc->cpu_p_blk = obj->Processor.PblkAddress;
175 	sc->cpu_p_blk_len = obj->Processor.PblkLength;
176 	AcpiOsFree(obj);
177 
178 	/* If this is the first device probed, check for quirks. */
179 	if (device_get_unit(dev) == 0)
180 		acpi_throttle_quirks(sc);
181 
182 	return (acpi_throttle_evaluate(sc));
183 }
184 
185 static int
186 acpi_throttle_evaluate(struct acpi_throttle_softc *sc)
187 {
188 	uint32_t duty_end;
189 	ACPI_BUFFER buf;
190 	ACPI_OBJECT obj;
191 	ACPI_GENERIC_ADDRESS gas;
192 	ACPI_STATUS status;
193 
194 	/* Get throttling parameters from the FADT.  0 means not supported. */
195 	if (device_get_unit(sc->cpu_dev) == 0) {
196 		cpu_duty_offset = AcpiGbl_FADT->DutyOffset;
197 		cpu_duty_width = AcpiGbl_FADT->DutyWidth;
198 	}
199 	if (cpu_duty_width == 0 || (thr_quirks & CPU_QUIRK_NO_THROTTLE) != 0)
200 		return (ENXIO);
201 
202 	/* Validate the duty offset/width. */
203 	duty_end = cpu_duty_offset + cpu_duty_width - 1;
204 	if (duty_end > 31) {
205 		device_printf(sc->cpu_dev,
206 		    "CLK_VAL field overflows P_CNT register\n");
207 		return (ENXIO);
208 	}
209 	if (cpu_duty_offset <= 4 && duty_end >= 4) {
210 		device_printf(sc->cpu_dev,
211 		    "CLK_VAL field overlaps THT_EN bit\n");
212 		return (ENXIO);
213 	}
214 
215 	/*
216 	 * If not present, fall back to using the processor's P_BLK to find
217 	 * the P_CNT register.
218 	 *
219 	 * Note that some systems seem to duplicate the P_BLK pointer
220 	 * across multiple CPUs, so not getting the resource is not fatal.
221 	 */
222 	buf.Pointer = &obj;
223 	buf.Length = sizeof(obj);
224 	status = AcpiEvaluateObject(sc->cpu_handle, "_PTC", NULL, &buf);
225 	if (ACPI_SUCCESS(status)) {
226 		if (obj.Buffer.Length < sizeof(ACPI_GENERIC_ADDRESS) + 3) {
227 			device_printf(sc->cpu_dev, "_PTC buffer too small\n");
228 			return (ENXIO);
229 		}
230 		memcpy(&gas, obj.Buffer.Pointer + 3, sizeof(gas));
231 		acpi_bus_alloc_gas(sc->cpu_dev, &sc->cpu_p_type, &thr_rid,
232 		    &gas, &sc->cpu_p_cnt);
233 		if (sc->cpu_p_cnt != NULL && bootverbose) {
234 			device_printf(sc->cpu_dev, "P_CNT from _PTC %#jx\n",
235 			    gas.Address);
236 		}
237 	}
238 
239 	/* If _PTC not present or other failure, try the P_BLK. */
240 	if (sc->cpu_p_cnt == NULL) {
241 		/*
242 		 * The spec says P_BLK must be 6 bytes long.  However, some
243 		 * systems use it to indicate a fractional set of features
244 		 * present so we take anything >= 4.
245 		 */
246 		if (sc->cpu_p_blk_len < 4)
247 			return (ENXIO);
248 		gas.Address = sc->cpu_p_blk;
249 		gas.AddressSpaceId = ACPI_ADR_SPACE_SYSTEM_IO;
250 		gas.RegisterBitWidth = 32;
251 		acpi_bus_alloc_gas(sc->cpu_dev, &sc->cpu_p_type, &thr_rid,
252 		    &gas, &sc->cpu_p_cnt);
253 		if (sc->cpu_p_cnt != NULL) {
254 			if (bootverbose)
255 				device_printf(sc->cpu_dev,
256 				    "P_CNT from P_BLK %#x\n", sc->cpu_p_blk);
257 		} else {
258 			device_printf(sc->cpu_dev, "failed to attach P_CNT\n");
259 			return (ENXIO);
260 		}
261 	}
262 	thr_rid++;
263 
264 	return (0);
265 }
266 
267 static int
268 acpi_throttle_quirks(struct acpi_throttle_softc *sc)
269 {
270 	device_t acpi_dev;
271 
272 	/* Look for various quirks of the PIIX4 part. */
273 	acpi_dev = pci_find_device(PCI_VENDOR_INTEL, PCI_DEVICE_82371AB_3);
274 	if (acpi_dev) {
275 		switch (pci_get_revid(acpi_dev)) {
276 		/*
277 		 * Disable throttling control on PIIX4 A and B-step.
278 		 * See specification changes #13 ("Manual Throttle Duty Cycle")
279 		 * and #14 ("Enabling and Disabling Manual Throttle"), plus
280 		 * erratum #5 ("STPCLK# Deassertion Time") from the January
281 		 * 2002 PIIX4 specification update.  Note that few (if any)
282 		 * mobile systems ever used this part.
283 		 */
284 		case PCI_REVISION_A_STEP:
285 		case PCI_REVISION_B_STEP:
286 			thr_quirks |= CPU_QUIRK_NO_THROTTLE;
287 			break;
288 		default:
289 			break;
290 		}
291 	}
292 
293 	return (0);
294 }
295 
296 static int
297 acpi_thr_settings(device_t dev, struct cf_setting *sets, int *count, int *type)
298 {
299 	struct acpi_throttle_softc *sc;
300 	int i, speed;
301 
302 	sc = device_get_softc(dev);
303 	if (sets == NULL || count == NULL)
304 		return (EINVAL);
305 	if (*count < CPU_MAX_SPEED)
306 		return (ENOMEM);
307 
308 	/* Return a list of valid settings for this driver. */
309 	memset(sets, CPUFREQ_VAL_UNKNOWN, sizeof(*sets) * CPU_MAX_SPEED);
310 	for (i = 0, speed = CPU_MAX_SPEED; speed != 0; i++, speed--) {
311 		sets[i].freq = CPU_SPEED_PERCENT(speed);
312 		sets[i].dev = dev;
313 	}
314 	*count = CPU_MAX_SPEED;
315 	*type = CPUFREQ_TYPE_RELATIVE;
316 
317 	return (0);
318 }
319 
320 static int
321 acpi_thr_set(device_t dev, const struct cf_setting *set)
322 {
323 	struct acpi_throttle_softc *sc;
324 	uint32_t clk_val, p_cnt, speed;
325 
326 	if (set == NULL)
327 		return (EINVAL);
328 	sc = device_get_softc(dev);
329 
330 	/*
331 	 * Validate requested state converts to a duty cycle that is an
332 	 * integer from [1 .. CPU_MAX_SPEED].
333 	 */
334 	speed = set->freq * CPU_MAX_SPEED / 10000;
335 	if (speed * 10000 != set->freq * CPU_MAX_SPEED ||
336 	    speed < 1 || speed > CPU_MAX_SPEED)
337 		return (EINVAL);
338 
339 	/* If we're at this setting, don't bother applying it again. */
340 	if (speed == cpu_throttle_state)
341 		return (0);
342 
343 	/* Get the current P_CNT value and disable throttling */
344 	p_cnt = THR_GET_REG(sc->cpu_p_cnt);
345 	p_cnt &= ~CPU_P_CNT_THT_EN;
346 	THR_SET_REG(sc->cpu_p_cnt, p_cnt);
347 
348 	/* If we're at maximum speed, that's all */
349 	if (speed < CPU_MAX_SPEED) {
350 		/* Mask the old CLK_VAL off and OR in the new value */
351 		clk_val = (CPU_MAX_SPEED - 1) << cpu_duty_offset;
352 		p_cnt &= ~clk_val;
353 		p_cnt |= (speed << cpu_duty_offset);
354 
355 		/* Write the new P_CNT value and then enable throttling */
356 		THR_SET_REG(sc->cpu_p_cnt, p_cnt);
357 		p_cnt |= CPU_P_CNT_THT_EN;
358 		THR_SET_REG(sc->cpu_p_cnt, p_cnt);
359 	}
360 	cpu_throttle_state = speed;
361 
362 	return (0);
363 }
364 
365 static int
366 acpi_thr_get(device_t dev, struct cf_setting *set)
367 {
368 	struct acpi_throttle_softc *sc;
369 	uint32_t p_cnt, clk_val;
370 
371 	if (set == NULL)
372 		return (EINVAL);
373 	sc = device_get_softc(dev);
374 
375 	/* Get the current throttling setting from P_CNT. */
376 	p_cnt = THR_GET_REG(sc->cpu_p_cnt);
377 	clk_val = (p_cnt >> cpu_duty_offset) & (CPU_MAX_SPEED - 1);
378 
379 	memset(set, CPUFREQ_VAL_UNKNOWN, sizeof(*set));
380 	set->freq = CPU_SPEED_PERCENT(clk_val);
381 	set->dev = dev;
382 
383 	return (0);
384 }
385