xref: /freebsd/sys/dev/acpica/acpi_cpu.c (revision 41466b50c1d5bfd1cf6adaae547a579a75d7c04e)
1 /*-
2  * Copyright (c) 2001 Michael Smith
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  *	$FreeBSD$
27  */
28 
29 #include "opt_acpi.h"
30 #include <sys/param.h>
31 #include <sys/kernel.h>
32 #include <sys/bus.h>
33 
34 #include <machine/bus_pio.h>
35 #include <machine/bus.h>
36 #include <machine/resource.h>
37 #include <sys/rman.h>
38 
39 #include "acpi.h"
40 
41 #include <dev/acpica/acpivar.h>
42 
43 /*
44  * Support for ACPI Processor devices.
45  *
46  * Note that this only provides ACPI 1.0 support (with the exception of the
47  * PSTATE_CNT field).  2.0 support will involve implementing _PTC, _PCT,
48  * _PSS and _PPC.
49  */
50 
51 /*
52  * Hooks for the ACPI CA debugging infrastructure
53  */
54 #define _COMPONENT	ACPI_PROCESSOR
55 MODULE_NAME("PROCESSOR")
56 
57 struct acpi_cpu_softc {
58     device_t		cpu_dev;
59     ACPI_HANDLE		cpu_handle;
60 
61     u_int32_t		cpu_id;
62 
63     /* CPU throttling control register */
64     struct resource	*cpu_p_blk;
65 #define CPU_GET_P_CNT(sc)	(bus_space_read_4(rman_get_bustag((sc)->cpu_p_blk), 	\
66 						  rman_get_bushandle((sc)->cpu_p_blk),	\
67 						  0))
68 #define CPU_SET_P_CNT(sc, val)	(bus_space_write_4(rman_get_bustag((sc)->cpu_p_blk), 	\
69 						  rman_get_bushandle((sc)->cpu_p_blk),	\
70 						  0, (val)))
71 #define CPU_P_CNT_THT_EN	(1<<4)
72 };
73 
74 /*
75  * Speeds are stored in counts, from 1 - CPU_MAX_SPEED, and
76  * reported to the user in tenths of a percent.
77  */
78 static u_int32_t	cpu_duty_offset;
79 static u_int32_t	cpu_duty_width;
80 #define CPU_MAX_SPEED		(1 << cpu_duty_width)
81 #define CPU_SPEED_PERCENT(x)	((1000 * (x)) / CPU_MAX_SPEED)
82 #define CPU_SPEED_PRINTABLE(x)	(CPU_SPEED_PERCENT(x) / 10),(CPU_SPEED_PERCENT(x) % 10)
83 
84 static u_int32_t	cpu_smi_cmd;	/* should be a generic way to do this */
85 static u_int8_t		cpu_pstate_cnt;
86 
87 static u_int32_t	cpu_current_state;
88 static u_int32_t	cpu_performance_state;
89 static u_int32_t	cpu_economy_state;
90 static u_int32_t	cpu_max_state;
91 
92 static device_t		*cpu_devices;
93 static int		cpu_ndevices;
94 
95 static struct sysctl_ctx_list	acpi_cpu_sysctl_ctx;
96 static struct sysctl_oid	*acpi_cpu_sysctl_tree;
97 
98 static int	acpi_cpu_probe(device_t dev);
99 static int	acpi_cpu_attach(device_t dev);
100 static void	acpi_cpu_init_throttling(void *arg);
101 static void	acpi_cpu_set_speed(u_int32_t speed);
102 static void	acpi_cpu_powerprofile(void *arg);
103 static int	acpi_cpu_speed_sysctl(SYSCTL_HANDLER_ARGS);
104 
105 static device_method_t acpi_cpu_methods[] = {
106     /* Device interface */
107     DEVMETHOD(device_probe,	acpi_cpu_probe),
108     DEVMETHOD(device_attach,	acpi_cpu_attach),
109 
110     {0, 0}
111 };
112 
113 static driver_t acpi_cpu_driver = {
114     "acpi_cpu",
115     acpi_cpu_methods,
116     sizeof(struct acpi_cpu_softc),
117 };
118 
119 devclass_t acpi_cpu_devclass;
120 DRIVER_MODULE(acpi_cpu, acpi, acpi_cpu_driver, acpi_cpu_devclass, 0, 0);
121 
122 static int
123 acpi_cpu_probe(device_t dev)
124 {
125     if (!acpi_disabled("cpu") &&
126 	(acpi_get_type(dev) == ACPI_TYPE_PROCESSOR)) {
127 	device_set_desc(dev, "CPU");	/* XXX get more verbose description? */
128 	return(0);
129     }
130     return(ENXIO);
131 }
132 
133 static int
134 acpi_cpu_attach(device_t dev)
135 {
136     struct acpi_cpu_softc	*sc;
137     struct acpi_softc		*acpi_sc;
138     ACPI_OBJECT			processor;
139     ACPI_BUFFER			buf;
140     ACPI_STATUS			status;
141     u_int32_t			p_blk;
142     u_int32_t			p_blk_length;
143     u_int32_t			duty_end;
144     int				rid;
145 
146     FUNCTION_TRACE(__func__);
147 
148     ACPI_ASSERTLOCK;
149 
150     sc = device_get_softc(dev);
151     sc->cpu_dev = dev;
152     sc->cpu_handle = acpi_get_handle(dev);
153 
154     /*
155      * Get global parameters from the FADT.
156      */
157     if (device_get_unit(sc->cpu_dev) == 0) {
158 	cpu_duty_offset = AcpiGbl_FADT->DutyOffset;
159 	cpu_duty_width = AcpiGbl_FADT->DutyWidth;
160 	cpu_smi_cmd = AcpiGbl_FADT->SmiCmd;
161 	cpu_pstate_cnt = AcpiGbl_FADT->PstateCnt;
162 
163 	/* validate the offset/width */
164 	duty_end = cpu_duty_offset + cpu_duty_width - 1;
165 	/* check that it fits */
166 	if (duty_end > 31) {
167 	    printf("acpi_cpu: CLK_VAL field overflows P_CNT register\n");
168 	    cpu_duty_width = 0;
169 	}
170 	/* check for overlap with the THT_EN bit */
171 	if ((cpu_duty_offset <= 4) && (duty_end >= 4)) {
172 	    printf("acpi_cpu: CLK_VAL field overlaps THT_EN bit\n");
173 	    cpu_duty_width = 0;
174 	}
175 
176 	/*
177 	 * Start the throttling process once the probe phase completes, if we think that
178 	 * it's going to be useful.  If the duty width value is zero, there are no significant
179 	 * bits in the register and thus no throttled states.
180 	 */
181 	if (cpu_duty_width > 0) {
182 	    AcpiOsQueueForExecution(OSD_PRIORITY_LO, acpi_cpu_init_throttling, NULL);
183 
184 	    acpi_sc = acpi_device_get_parent_softc(dev);
185 	    sysctl_ctx_init(&acpi_cpu_sysctl_ctx);
186 	    acpi_cpu_sysctl_tree = SYSCTL_ADD_NODE(&acpi_cpu_sysctl_ctx,
187 						  SYSCTL_CHILDREN(acpi_sc->acpi_sysctl_tree),
188 						  OID_AUTO, "cpu", CTLFLAG_RD, 0, "");
189 
190 	    SYSCTL_ADD_INT(&acpi_cpu_sysctl_ctx, SYSCTL_CHILDREN(acpi_cpu_sysctl_tree),
191 			   OID_AUTO, "max_speed", CTLFLAG_RD,
192 			   &cpu_max_state, 0, "maximum CPU speed");
193 	    SYSCTL_ADD_INT(&acpi_cpu_sysctl_ctx, SYSCTL_CHILDREN(acpi_cpu_sysctl_tree),
194 			   OID_AUTO, "current_speed", CTLFLAG_RD,
195 			   &cpu_current_state, 0, "current CPU speed");
196 	    SYSCTL_ADD_PROC(&acpi_cpu_sysctl_ctx, SYSCTL_CHILDREN(acpi_cpu_sysctl_tree),
197 			    OID_AUTO, "performance_speed", CTLTYPE_INT | CTLFLAG_RW,
198 			    &cpu_performance_state, 0, acpi_cpu_speed_sysctl, "I", "");
199 	    SYSCTL_ADD_PROC(&acpi_cpu_sysctl_ctx, SYSCTL_CHILDREN(acpi_cpu_sysctl_tree),
200 			    OID_AUTO, "economy_speed", CTLTYPE_INT | CTLFLAG_RW,
201 			    &cpu_economy_state, 0, acpi_cpu_speed_sysctl, "I", "");
202 	}
203     }
204 
205     /*
206      * Get the processor object.
207      */
208     buf.Pointer = &processor;
209     buf.Length = sizeof(processor);
210     if (ACPI_FAILURE(status = AcpiEvaluateObject(sc->cpu_handle, NULL, NULL, &buf))) {
211 	device_printf(sc->cpu_dev, "couldn't get Processor object - %s\n", AcpiFormatException(status));
212 	return_VALUE(ENXIO);
213     }
214     if (processor.Type != ACPI_TYPE_PROCESSOR) {
215 	device_printf(sc->cpu_dev, "Processor object has bad type %d\n", processor.Type);
216 	return_VALUE(ENXIO);
217     }
218     sc->cpu_id = processor.Processor.ProcId;
219 
220     /*
221      * If it looks like we support throttling, find this CPU's P_BLK.
222      *
223      * Note that some systems seem to duplicate the P_BLK pointer across
224      * multiple CPUs, so not getting the resource is not fatal.
225      *
226      * XXX should support _PTC here as well, once we work out how to parse it.
227      *
228      * XXX is it valid to assume that the P_BLK must be 6 bytes long?
229      */
230     if (cpu_duty_width > 0) {
231 	p_blk = processor.Processor.PblkAddress;
232 	p_blk_length = processor.Processor.PblkLength;
233 
234 	/* allocate bus space if possible */
235 	if ((p_blk > 0) && (p_blk_length == 6)) {
236 	    rid = 0;
237 	    bus_set_resource(sc->cpu_dev, SYS_RES_IOPORT, rid, p_blk, p_blk_length);
238 	    sc->cpu_p_blk = bus_alloc_resource(sc->cpu_dev, SYS_RES_IOPORT, &rid, 0, ~0, 1,
239 					       RF_ACTIVE);
240 
241 	    ACPI_DEBUG_PRINT((ACPI_DB_IO, "acpi_cpu%d: throttling with P_BLK at 0x%x/%d%s\n",
242 			      device_get_unit(sc->cpu_dev), p_blk, p_blk_length,
243 			      sc->cpu_p_blk ? "" : " (shadowed)"));
244 	}
245     }
246     return_VALUE(0);
247 }
248 
249 /*
250  * Call this *after* all CPUs have been attached.
251  *
252  * Takes the ACPI lock to avoid fighting anyone over the SMI command
253  * port.  Could probably lock less code.
254  */
255 static void
256 acpi_cpu_init_throttling(void *arg)
257 {
258     int cpu_temp_speed;
259 
260     ACPI_LOCK;
261 
262     /* get set of CPU devices */
263     devclass_get_devices(acpi_cpu_devclass, &cpu_devices, &cpu_ndevices);
264 
265     /* initialise throttling states */
266     cpu_max_state = CPU_MAX_SPEED;
267     cpu_performance_state = cpu_max_state;
268     cpu_economy_state = cpu_performance_state / 2;
269     if (cpu_economy_state == 0)		/* 0 is 'reserved' */
270 	cpu_economy_state++;
271     if (TUNABLE_INT_FETCH("hw.acpi.cpu.performance_speed",
272 	&cpu_temp_speed) && cpu_temp_speed > 0 &&
273 	cpu_temp_speed <= cpu_max_state)
274 	cpu_performance_state = cpu_temp_speed;
275     if (TUNABLE_INT_FETCH("hw.acpi.cpu.economy_speed",
276 	&cpu_temp_speed) && cpu_temp_speed > 0 &&
277 	cpu_temp_speed <= cpu_max_state)
278 	cpu_economy_state = cpu_temp_speed;
279 
280     /* register performance profile change handler */
281     EVENTHANDLER_REGISTER(powerprofile_change, acpi_cpu_powerprofile, NULL, 0);
282 
283     /* if ACPI 2.0+, signal platform that we are taking over throttling */
284     if (cpu_pstate_cnt != 0) {
285 	/* XXX should be a generic interface for this */
286 	AcpiOsWritePort(cpu_smi_cmd, cpu_pstate_cnt, 8);
287     }
288 
289     ACPI_UNLOCK;
290 
291     /* set initial speed */
292     acpi_cpu_powerprofile(NULL);
293 
294     printf("acpi_cpu: CPU throttling enabled, %d steps from 100%% to %d.%d%%\n",
295 	   CPU_MAX_SPEED, CPU_SPEED_PRINTABLE(1));
296 }
297 
298 /*
299  * Set CPUs to the new state.
300  *
301  * Must be called with the ACPI lock held.
302  */
303 static void
304 acpi_cpu_set_speed(u_int32_t speed)
305 {
306     struct acpi_cpu_softc	*sc;
307     int				i;
308     u_int32_t			p_cnt, clk_val;
309 
310     ACPI_ASSERTLOCK;
311 
312     /* iterate over processors */
313     for (i = 0; i < cpu_ndevices; i++) {
314 	sc = device_get_softc(cpu_devices[i]);
315 	if (sc->cpu_p_blk == NULL)
316 	    continue;
317 
318 	/* get the current P_CNT value and disable throttling */
319 	p_cnt = CPU_GET_P_CNT(sc);
320 	p_cnt &= ~CPU_P_CNT_THT_EN;
321 	CPU_SET_P_CNT(sc, p_cnt);
322 
323 	/* if we're at maximum speed, that's all */
324 	if (speed < CPU_MAX_SPEED) {
325 
326 	    /* mask the old CLK_VAL off and or-in the new value */
327 	    clk_val = CPU_MAX_SPEED << cpu_duty_offset;
328 	    p_cnt &= ~clk_val;
329 	    p_cnt |= (speed << cpu_duty_offset);
330 
331 	    /* write the new P_CNT value and then enable throttling */
332 	    CPU_SET_P_CNT(sc, p_cnt);
333 	    p_cnt |= CPU_P_CNT_THT_EN;
334 	    CPU_SET_P_CNT(sc, p_cnt);
335 	}
336 	device_printf(sc->cpu_dev, "set speed to %d.%d%%\n", CPU_SPEED_PRINTABLE(speed));
337     }
338     cpu_current_state = speed;
339 }
340 
341 /*
342  * Power profile change hook.
343  *
344  * Uses the ACPI lock to avoid reentrancy.
345  */
346 static void
347 acpi_cpu_powerprofile(void *arg)
348 {
349     u_int32_t	new;
350 
351     ACPI_LOCK;
352 
353     new = (powerprofile_get_state() == POWERPROFILE_PERFORMANCE) ? cpu_performance_state : cpu_economy_state;
354     if (cpu_current_state != new)
355 	acpi_cpu_set_speed(new);
356 
357     ACPI_UNLOCK;
358 }
359 
360 /*
361  * Handle changes in the performance/ecomony CPU settings.
362  *
363  * Does not need the ACPI lock (although setting *argp should
364  * probably be atomic).
365  */
366 static int
367 acpi_cpu_speed_sysctl(SYSCTL_HANDLER_ARGS)
368 {
369     u_int32_t	*argp;
370     u_int32_t	arg;
371     int		error;
372 
373     argp = (u_int32_t *)oidp->oid_arg1;
374     arg = *argp;
375     error = sysctl_handle_int(oidp, &arg, 0, req);
376 
377     /* error or no new value */
378     if ((error != 0) || (req->newptr == NULL))
379 	return(error);
380 
381     /* range check */
382     if ((arg < 1) || (arg > cpu_max_state))
383 	return(EINVAL);
384 
385     /* set new value and possibly switch */
386     *argp = arg;
387     acpi_cpu_powerprofile(NULL);
388 
389     return(0);
390 }
391