xref: /openbsd/sys/dev/acpi/acpicpu.c (revision 8932bfb7)
1 /* $OpenBSD: acpicpu.c,v 1.57 2010/07/21 19:35:15 deraadt Exp $ */
2 /*
3  * Copyright (c) 2005 Marco Peereboom <marco@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <sys/param.h>
19 #include <sys/proc.h>
20 #include <sys/signalvar.h>
21 #include <sys/sysctl.h>
22 #include <sys/systm.h>
23 #include <sys/device.h>
24 #include <sys/malloc.h>
25 #include <sys/queue.h>
26 
27 #include <machine/bus.h>
28 #include <machine/cpu.h>
29 #include <machine/cpufunc.h>
30 #include <machine/specialreg.h>
31 
32 #include <dev/acpi/acpireg.h>
33 #include <dev/acpi/acpivar.h>
34 #include <dev/acpi/acpidev.h>
35 #include <dev/acpi/amltypes.h>
36 #include <dev/acpi/dsdt.h>
37 
38 #include <sys/sensors.h>
39 
40 int	acpicpu_match(struct device *, void *, void *);
41 void	acpicpu_attach(struct device *, struct device *, void *);
42 int	acpicpu_notify(struct aml_node *, int, void *);
43 void	acpicpu_setperf(int);
44 void	acpicpu_setperf_ppc_change(struct acpicpu_pss *, int);
45 
46 #define ACPI_STATE_C0		0x00
47 #define ACPI_STATE_C1		0x01
48 #define ACPI_STATE_C2		0x02
49 #define ACPI_STATE_C3		0x03
50 
51 #define ACPI_PDC_REVID		0x1
52 #define ACPI_PDC_SMP		0xa
53 #define ACPI_PDC_MSR		0x1
54 
55 /* _PDC Intel capabilities flags from linux */
56 #define ACPI_PDC_P_FFH		0x0001
57 #define ACPI_PDC_C_C1_HALT	0x0002
58 #define ACPI_PDC_T_FFH		0x0004
59 #define ACPI_PDC_SMP_C1PT	0x0008
60 #define ACPI_PDC_SMP_C2C3	0x0010
61 #define ACPI_PDC_SMP_P_SWCOORD	0x0020
62 #define ACPI_PDC_SMP_C_SWCOORD	0x0040
63 #define ACPI_PDC_SMP_T_SWCOORD	0x0080
64 #define ACPI_PDC_C_C1_FFH	0x0100
65 #define ACPI_PDC_C_C2C3_FFH	0x0200
66 
67 #define FLAGS_NO_C2		0x01
68 #define FLAGS_NO_C3		0x02
69 #define FLAGS_BMCHECK		0x04
70 #define FLAGS_NOTHROTTLE	0x08
71 #define FLAGS_NOPSS		0x10
72 #define FLAGS_NOPCT		0x20
73 
74 #define CPU_THT_EN		(1L << 4)
75 #define CPU_MAXSTATE(sc)	(1L << (sc)->sc_duty_wid)
76 #define CPU_STATE(sc,pct)	((pct * CPU_MAXSTATE(sc) / 100) << (sc)->sc_duty_off)
77 #define CPU_STATEMASK(sc)	((CPU_MAXSTATE(sc) - 1) << (sc)->sc_duty_off)
78 
79 #define ACPI_MAX_C2_LATENCY	100
80 #define ACPI_MAX_C3_LATENCY	1000
81 
82 /* Make sure throttling bits are valid,a=addr,o=offset,w=width */
83 #define valid_throttle(o,w,a)	(a && w && (o+w)<=31 && (o>4 || (o+w)<=4))
84 
85 struct acpi_cstate
86 {
87 	int	 type;
88 	int	 latency;
89 	int	 power;
90 	int	 address;
91 
92 	SLIST_ENTRY(acpi_cstate) link;
93 };
94 
95 struct acpicpu_softc {
96 	struct device		sc_dev;
97 	int			sc_cpu;
98 
99 	int			sc_duty_wid;
100 	int			sc_duty_off;
101 	int			sc_pblk_addr;
102 	int			sc_pblk_len;
103 	int			sc_flags;
104 
105 	SLIST_HEAD(,acpi_cstate) sc_cstates;
106 
107 	bus_space_tag_t		sc_iot;
108 	bus_space_handle_t	sc_ioh;
109 
110 	struct acpi_softc	*sc_acpi;
111 	struct aml_node		*sc_devnode;
112 
113 	int			sc_pss_len;
114 	int			sc_ppc;
115 	int			sc_level;
116 	struct acpicpu_pss	*sc_pss;
117 
118 	struct acpicpu_pct	sc_pct;
119 	/* save compensation for pct access for lying bios' */
120 	u_int32_t		sc_pct_stat_as;
121 	u_int32_t		sc_pct_ctrl_as;
122 	u_int32_t		sc_pct_stat_len;
123 	u_int32_t		sc_pct_ctrl_len;
124 	/*
125 	 * XXX: _PPC Change listener
126 	 * PPC changes can occur when for example a machine is disconnected
127 	 * from AC power and can no loger support the highest frequency or
128 	 * voltage when driven from the battery.
129 	 * Should probably be reimplemented as a list for now we assume only
130 	 * one listener
131 	 */
132 	void			(*sc_notify)(struct acpicpu_pss *, int);
133 };
134 
135 void    acpicpu_add_cstatepkg(struct aml_value *, void *);
136 int	acpicpu_getppc(struct acpicpu_softc *);
137 int	acpicpu_getpct(struct acpicpu_softc *);
138 int	acpicpu_getpss(struct acpicpu_softc *);
139 struct acpi_cstate *acpicpu_add_cstate(struct acpicpu_softc *, int, int, int,
140     int);
141 void	acpicpu_set_pdc(struct acpicpu_softc *);
142 
143 #if 0
144 void    acpicpu_set_throttle(struct acpicpu_softc *, int);
145 struct acpi_cstate *acpicpu_find_cstate(struct acpicpu_softc *, int);
146 #endif
147 
148 struct cfattach acpicpu_ca = {
149 	sizeof(struct acpicpu_softc), acpicpu_match, acpicpu_attach
150 };
151 
152 struct cfdriver acpicpu_cd = {
153 	NULL, "acpicpu", DV_DULL
154 };
155 
156 extern int setperf_prio;
157 
158 struct acpicpu_softc *acpicpu_sc[MAXCPUS];
159 
160 #if 0
161 void
162 acpicpu_set_throttle(struct acpicpu_softc *sc, int level)
163 {
164 	uint32_t pbval;
165 
166 	if (sc->sc_flags & FLAGS_NOTHROTTLE)
167 		return;
168 
169 	/* Disable throttling control */
170 	pbval = inl(sc->sc_pblk_addr);
171 	outl(sc->sc_pblk_addr, pbval & ~CPU_THT_EN);
172 	if (level < 100) {
173 		pbval &= ~CPU_STATEMASK(sc);
174 		pbval |= CPU_STATE(sc, level);
175 		outl(sc->sc_pblk_addr, pbval & ~CPU_THT_EN);
176 		outl(sc->sc_pblk_addr, pbval | CPU_THT_EN);
177 	}
178 }
179 
180 struct acpi_cstate *
181 acpicpu_find_cstate(struct acpicpu_softc *sc, int type)
182 {
183 	struct acpi_cstate	*cx;
184 
185 	SLIST_FOREACH(cx, &sc->sc_cstates, link)
186 		if (cx->type == type)
187 			return cx;
188 	return (NULL);
189 }
190 #endif
191 
192 
193 void
194 acpicpu_set_pdc(struct acpicpu_softc *sc)
195 {
196 	struct aml_value cmd, osc_cmd[4];
197 	struct aml_value res;
198 	uint32_t buf[3];
199 
200 	/* 4077A616-290C-47BE-9EBD-D87058713953 */
201 	static uint8_t cpu_oscuuid[16] = { 0x16, 0xA6, 0x77, 0x40, 0x0C, 0x29,
202 					   0xBE, 0x47, 0x9E, 0xBD, 0xD8, 0x70,
203 					   0x58, 0x71, 0x39, 0x53 };
204 	/* Evaluate _PDC */
205 	memset(&cmd, 0, sizeof(cmd));
206 	cmd.type = AML_OBJTYPE_BUFFER;
207 	cmd.v_buffer = (uint8_t *)&buf;
208 	cmd.length = sizeof(buf);
209 
210 	buf[0] = ACPI_PDC_REVID;
211 	buf[1] = 1;
212 	buf[2] = ACPI_PDC_C_C1_HALT | ACPI_PDC_P_FFH | ACPI_PDC_C_C1_FFH
213 	    | ACPI_PDC_C_C2C3_FFH | ACPI_PDC_SMP_P_SWCOORD | ACPI_PDC_SMP_C2C3
214 	    | ACPI_PDC_SMP_C1PT;
215 
216 	aml_evalname(sc->sc_acpi, sc->sc_devnode, "_PDC", 1, &cmd, &res);
217 
218 	/* Evaluate _OSC */
219 	memset(&osc_cmd, 0, sizeof(cmd) * 4);
220 	osc_cmd[0].type = AML_OBJTYPE_BUFFER;
221 	osc_cmd[0].v_buffer = (uint8_t *)&cpu_oscuuid;
222 	osc_cmd[0].length = sizeof(cpu_oscuuid);
223 
224 	osc_cmd[1].type = AML_OBJTYPE_INTEGER;
225 	osc_cmd[1].v_integer = 1;
226 	osc_cmd[1].length = 1;
227 
228 	osc_cmd[2].type = AML_OBJTYPE_INTEGER;
229 	osc_cmd[2].v_integer = 1;
230 	osc_cmd[2].length = 1;
231 
232 	buf[0] = 0;
233 	osc_cmd[3].type = AML_OBJTYPE_BUFFER;
234 	osc_cmd[3].v_buffer = (int8_t *)&buf;
235 	osc_cmd[3].length = sizeof(buf);
236 
237 	aml_evalname(sc->sc_acpi, sc->sc_devnode, "_OSC", 4, osc_cmd, &res);
238 }
239 
240 
241 struct acpi_cstate *
242 acpicpu_add_cstate(struct acpicpu_softc *sc, int type, int latency, int power,
243     int address)
244 {
245 	struct acpi_cstate	*cx;
246 
247 	dnprintf(10," C%d: latency:.%4x power:%.4x addr:%.8x\n",
248 	    type, latency, power, address);
249 
250 	switch (type) {
251 	case ACPI_STATE_C2:
252 		if (latency > ACPI_MAX_C2_LATENCY || !address ||
253 		    (sc->sc_flags & FLAGS_NO_C2))
254 			goto bad;
255 		break;
256 	case ACPI_STATE_C3:
257 		if (latency > ACPI_MAX_C3_LATENCY || !address ||
258 		    (sc->sc_flags & FLAGS_NO_C3))
259 			goto bad;
260 		break;
261 	}
262 
263 	cx = malloc(sizeof(*cx), M_DEVBUF, M_WAITOK | M_ZERO);
264 
265 	cx->type = type;
266 	cx->power = power;
267 	cx->latency = latency;
268 	cx->address = address;
269 
270 	SLIST_INSERT_HEAD(&sc->sc_cstates, cx, link);
271 
272 	return (cx);
273  bad:
274 	dprintf("acpicpu%d: C%d not supported", sc->sc_cpu, type);
275 	return (NULL);
276 }
277 
278 /* Found a _CST object, add new cstate for each entry */
279 void
280 acpicpu_add_cstatepkg(struct aml_value *val, void *arg)
281 {
282 	struct acpicpu_softc	*sc = arg;
283 
284 #if defined(ACPI_DEBUG) && !defined(SMALL_KERNEL)
285 	aml_showvalue(val, 0);
286 #endif
287 	if (val->type != AML_OBJTYPE_PACKAGE || val->length != 4)
288 		return;
289 
290 	acpicpu_add_cstate(sc, val->v_package[1]->v_integer,
291 	    val->v_package[2]->v_integer,
292 	    val->v_package[3]->v_integer, -1);
293 }
294 
295 
296 int
297 acpicpu_match(struct device *parent, void *match, void *aux)
298 {
299 	struct acpi_attach_args	*aa = aux;
300 	struct cfdata		*cf = match;
301 
302 	/* sanity */
303 	if (aa->aaa_name == NULL ||
304 	    strcmp(aa->aaa_name, cf->cf_driver->cd_name) != 0 ||
305 	    aa->aaa_table != NULL)
306 		return (0);
307 
308 	return (1);
309 }
310 
311 void
312 acpicpu_attach(struct device *parent, struct device *self, void *aux)
313 {
314 	struct acpicpu_softc	*sc = (struct acpicpu_softc *)self;
315 	struct acpi_attach_args *aa = aux;
316 	struct aml_value	res;
317 	int			i;
318 	struct acpi_cstate	*cx;
319 	u_int32_t		status = 0;
320 
321 	sc->sc_acpi = (struct acpi_softc *)parent;
322 	sc->sc_devnode = aa->aaa_node;
323 	acpicpu_sc[sc->sc_dev.dv_unit] = sc;
324 
325 	SLIST_INIT(&sc->sc_cstates);
326 
327 	sc->sc_pss = NULL;
328 
329 	if (aml_evalnode(sc->sc_acpi, sc->sc_devnode, 0, NULL, &res) == 0) {
330 		if (res.type == AML_OBJTYPE_PROCESSOR) {
331 			sc->sc_cpu = res.v_processor.proc_id;
332 			sc->sc_pblk_addr = res.v_processor.proc_addr;
333 			sc->sc_pblk_len = res.v_processor.proc_len;
334 		}
335 		aml_freevalue(&res);
336 	}
337 	sc->sc_duty_off = sc->sc_acpi->sc_fadt->duty_offset;
338 	sc->sc_duty_wid = sc->sc_acpi->sc_fadt->duty_width;
339 
340 	acpicpu_set_pdc(sc);
341 
342 	if (!valid_throttle(sc->sc_duty_off, sc->sc_duty_wid, sc->sc_pblk_addr))
343 		sc->sc_flags |= FLAGS_NOTHROTTLE;
344 #ifdef ACPI_DEBUG
345 	printf(": %s: ", sc->sc_devnode->name);
346 	printf("\n: hdr:%x pblk:%x,%x duty:%x,%x pstate:%x "
347 	       "(%d throttling states)\n", sc->sc_acpi->sc_fadt->hdr_revision,
348 		sc->sc_pblk_addr, sc->sc_pblk_len, sc->sc_duty_off,
349 		sc->sc_duty_wid, sc->sc_acpi->sc_fadt->pstate_cnt,
350 		CPU_MAXSTATE(sc));
351 #endif
352 
353 	/* Get C-States from _CST or FADT */
354 	if (!aml_evalname(sc->sc_acpi, sc->sc_devnode, "_CST", 0, NULL, &res)) {
355 		aml_foreachpkg(&res, 1, acpicpu_add_cstatepkg, sc);
356 		aml_freevalue(&res);
357 	}
358 	else {
359 		/* Some systems don't export a full PBLK reduce functionality */
360 		if (sc->sc_pblk_len < 5)
361 			sc->sc_flags |= FLAGS_NO_C2;
362 		if (sc->sc_pblk_len < 6)
363 			sc->sc_flags |= FLAGS_NO_C3;
364 		acpicpu_add_cstate(sc, ACPI_STATE_C2,
365 		    sc->sc_acpi->sc_fadt->p_lvl2_lat, -1,
366 		    sc->sc_pblk_addr + 4);
367 		acpicpu_add_cstate(sc, ACPI_STATE_C3,
368 		    sc->sc_acpi->sc_fadt->p_lvl3_lat, -1,
369 		    sc->sc_pblk_addr + 5);
370 	}
371 	if (acpicpu_getpss(sc)) {
372 		sc->sc_flags |= FLAGS_NOPSS;
373 	} else {
374 #ifdef ACPI_DEBUG
375 		for (i = 0; i < sc->sc_pss_len; i++) {
376 			dnprintf(20, "%d %d %d %d %d %d\n",
377 			    sc->sc_pss[i].pss_core_freq,
378 			    sc->sc_pss[i].pss_power,
379 			    sc->sc_pss[i].pss_trans_latency,
380 			    sc->sc_pss[i].pss_bus_latency,
381 			    sc->sc_pss[i].pss_ctrl,
382 			    sc->sc_pss[i].pss_status);
383 		}
384 		dnprintf(20, "\n");
385 #endif
386 		if (sc->sc_pss_len == 0) {
387 			/* this should never happen */
388 			printf("%s: invalid _PSS length\n", DEVNAME(sc));
389 			sc->sc_flags |= FLAGS_NOPSS;
390 		}
391 
392 		acpicpu_getppc(sc);
393 		if (acpicpu_getpct(sc))
394 			sc->sc_flags |= FLAGS_NOPCT;
395 		else if (sc->sc_pss_len > 0) {
396 			/* Notify BIOS we are handing p-states */
397 			if (sc->sc_acpi->sc_fadt->pstate_cnt)
398 				acpi_write_pmreg(sc->sc_acpi, ACPIREG_SMICMD, 0,
399 				sc->sc_acpi->sc_fadt->pstate_cnt);
400 
401 			aml_register_notify(sc->sc_devnode, NULL,
402 			    acpicpu_notify, sc, ACPIDEV_NOPOLL);
403 
404 			acpi_gasio(sc->sc_acpi, ACPI_IOREAD,
405 			    sc->sc_pct.pct_status.grd_gas.address_space_id,
406 			    sc->sc_pct.pct_status.grd_gas.address,
407 			    sc->sc_pct_stat_as, sc->sc_pct_stat_as, &status);
408 			sc->sc_level = (100 / sc->sc_pss_len) *
409 			    (sc->sc_pss_len - status);
410 			dnprintf(20, "%s: cpu index %d, percentage %d\n",
411 			    DEVNAME(sc), status, sc->sc_level);
412 			if (setperf_prio < 30) {
413 				cpu_setperf = acpicpu_setperf;
414 				acpicpu_set_notify(acpicpu_setperf_ppc_change);
415 				setperf_prio = 30;
416 				acpi_hasprocfvs = 1;
417 			}
418 		}
419 	}
420 
421 	/*
422 	 * Nicely enumerate what power management capabilities
423 	 * ACPI CPU provides.
424 	 */
425 	if (!SLIST_EMPTY(&sc->sc_cstates)) {
426 		printf(":");
427 
428 		i = 0;
429 		SLIST_FOREACH(cx, &sc->sc_cstates, link) {
430 			if (i++)
431 				printf(",");
432 			switch (cx->type) {
433 			case ACPI_STATE_C0:
434 				printf(" C0");
435 				break;
436 			case ACPI_STATE_C1:
437 				printf(" C1");
438 				break;
439 			case ACPI_STATE_C2:
440 				printf(" C2");
441 				break;
442 			case ACPI_STATE_C3:
443 				printf(" C3");
444 				break;
445 			}
446 		}
447 	}
448 
449 	if (!(sc->sc_flags & (FLAGS_NOPSS | FLAGS_NOPCT)) ||
450 	    !(sc->sc_flags & FLAGS_NOPSS)) {
451 		printf("%c ", SLIST_EMPTY(&sc->sc_cstates) ? ':' : ',');
452 
453 		/*
454 		 * If acpicpu is itself providing the capability to transition
455 		 * states, enumerate them in the fashion that est and powernow
456 		 * would.
457 		 */
458 		if (!(sc->sc_flags & (FLAGS_NOPSS | FLAGS_NOPCT))) {
459 			printf("FVS, ");
460 			for (i = 0; i < sc->sc_pss_len - 1; i++)
461 				printf("%d, ", sc->sc_pss[i].pss_core_freq);
462 			printf("%d MHz", sc->sc_pss[i].pss_core_freq);
463 		} else
464 			printf("PSS");
465 	}
466 
467 	printf("\n");
468 }
469 
470 int
471 acpicpu_getppc(struct acpicpu_softc *sc)
472 {
473 	struct aml_value	res;
474 
475 	sc->sc_ppc = 0;
476 
477 	if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_PPC", 0, NULL, &res)) {
478 		dnprintf(10, "%s: no _PPC\n", DEVNAME(sc));
479 		return (1);
480 	}
481 
482 	sc->sc_ppc = aml_val2int(&res);
483 	dnprintf(10, "%s: _PPC: %d\n", DEVNAME(sc), sc->sc_ppc);
484 	aml_freevalue(&res);
485 
486 	return (0);
487 }
488 
489 int
490 acpicpu_getpct(struct acpicpu_softc *sc)
491 {
492 	struct aml_value	res;
493 	int			rv = 1;
494 
495 	if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_PCT", 0, NULL, &res)) {
496 		dnprintf(20, "%s: no _PCT\n", DEVNAME(sc));
497 		return (1);
498 	}
499 
500 	if (res.length != 2) {
501 		dnprintf(20, "%s: %s: invalid _PCT length\n", DEVNAME(sc),
502 		    sc->sc_devnode->name);
503 		return (1);
504 	}
505 
506 	memcpy(&sc->sc_pct.pct_ctrl, res.v_package[0]->v_buffer,
507 	    sizeof sc->sc_pct.pct_ctrl);
508 	if (sc->sc_pct.pct_ctrl.grd_gas.address_space_id ==
509 	    GAS_FUNCTIONAL_FIXED) {
510 		dnprintf(20, "CTRL GASIO is functional fixed hardware.\n");
511 		goto ffh;
512 	}
513 
514 	memcpy(&sc->sc_pct.pct_status, res.v_package[1]->v_buffer,
515 	    sizeof sc->sc_pct.pct_status);
516 	if (sc->sc_pct.pct_status.grd_gas.address_space_id ==
517 	    GAS_FUNCTIONAL_FIXED) {
518 		dnprintf(20, "CTRL GASIO is functional fixed hardware.\n");
519 		goto ffh;
520 	}
521 
522 	dnprintf(10, "_PCT(ctrl)  : %02x %04x %02x %02x %02x %02x %016x\n",
523 	    sc->sc_pct.pct_ctrl.grd_descriptor,
524 	    sc->sc_pct.pct_ctrl.grd_length,
525 	    sc->sc_pct.pct_ctrl.grd_gas.address_space_id,
526 	    sc->sc_pct.pct_ctrl.grd_gas.register_bit_width,
527 	    sc->sc_pct.pct_ctrl.grd_gas.register_bit_offset,
528 	    sc->sc_pct.pct_ctrl.grd_gas.access_size,
529 	    sc->sc_pct.pct_ctrl.grd_gas.address);
530 
531 	dnprintf(10, "_PCT(status): %02x %04x %02x %02x %02x %02x %016x\n",
532 	    sc->sc_pct.pct_status.grd_descriptor,
533 	    sc->sc_pct.pct_status.grd_length,
534 	    sc->sc_pct.pct_status.grd_gas.address_space_id,
535 	    sc->sc_pct.pct_status.grd_gas.register_bit_width,
536 	    sc->sc_pct.pct_status.grd_gas.register_bit_offset,
537 	    sc->sc_pct.pct_status.grd_gas.access_size,
538 	    sc->sc_pct.pct_status.grd_gas.address);
539 
540 	/* if not set assume single 32 bit access */
541 	sc->sc_pct_stat_as = sc->sc_pct.pct_status.grd_gas.register_bit_width
542 	    / 8;
543 	if (sc->sc_pct_stat_as == 0)
544 		sc->sc_pct_stat_as = 4;
545 	sc->sc_pct_ctrl_as = sc->sc_pct.pct_ctrl.grd_gas.register_bit_width / 8;
546 	if (sc->sc_pct_ctrl_as == 0)
547 		sc->sc_pct_ctrl_as = 4;
548 	sc->sc_pct_stat_len = sc->sc_pct.pct_status.grd_gas.access_size;
549 	if (sc->sc_pct_stat_len == 0)
550 		sc->sc_pct_stat_len = sc->sc_pct_stat_as;
551 	sc->sc_pct_ctrl_len = sc->sc_pct.pct_ctrl.grd_gas.access_size;
552 	if (sc->sc_pct_ctrl_len == 0)
553 		sc->sc_pct_ctrl_len = sc->sc_pct_ctrl_as;
554 
555 	rv = 0;
556 ffh:
557 	aml_freevalue(&res);
558 	return (rv);
559 }
560 
561 int
562 acpicpu_getpss(struct acpicpu_softc *sc)
563 {
564 	struct aml_value	res;
565 	int			i, c, cf;
566 
567 	if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_PSS", 0, NULL, &res)) {
568 		dprintf("%s: no _PSS\n", DEVNAME(sc));
569 		return (1);
570 	}
571 
572 	if (sc->sc_pss)
573 		free(sc->sc_pss, M_DEVBUF);
574 
575 	sc->sc_pss = malloc(res.length * sizeof *sc->sc_pss, M_DEVBUF,
576 	    M_WAITOK | M_ZERO);
577 
578 	c = 0;
579 	for (i = 0; i < res.length; i++) {
580 		cf = aml_val2int(res.v_package[i]->v_package[0]);
581 
582 		/* This heuristic comes from FreeBSDs
583 		 * dev/acpica/acpi_perf.c to weed out invalid PSS entries.
584 		 */
585 		if (cf == sc->sc_pss[c].pss_core_freq) {
586 			printf("%s: struck PSS entry, core frequency equals "
587 			    " last\n", sc->sc_dev.dv_xname);
588 			continue;
589 		}
590 
591 		if (cf == 0xFFFF || cf == 0x9999 || cf == 99999 || cf == 0) {
592 			printf("%s: struck PSS entry, inappropriate core "
593 			    "frequency value\n", sc->sc_dev.dv_xname);
594 			continue;
595 		}
596 
597 		sc->sc_pss[c].pss_core_freq = cf;
598 		sc->sc_pss[c].pss_power = aml_val2int(
599 		    res.v_package[i]->v_package[1]);
600 		sc->sc_pss[c].pss_trans_latency = aml_val2int(
601 		    res.v_package[i]->v_package[2]);
602 		sc->sc_pss[c].pss_bus_latency = aml_val2int(
603 		    res.v_package[i]->v_package[3]);
604 		sc->sc_pss[c].pss_ctrl = aml_val2int(
605 		    res.v_package[i]->v_package[4]);
606 		sc->sc_pss[c].pss_status = aml_val2int(
607 		    res.v_package[i]->v_package[5]);
608 		c++;
609 	}
610 	sc->sc_pss_len = c;
611 
612 	aml_freevalue(&res);
613 
614 	return (0);
615 }
616 
617 int
618 acpicpu_fetch_pss(struct acpicpu_pss **pss)
619 {
620 	struct acpicpu_softc	*sc;
621 
622 	/*
623 	 * XXX: According to the ACPI spec in an SMP system all processors
624 	 * are supposed to support the same states. For now we pray
625 	 * the bios ensures this...
626 	 */
627 
628 	sc = acpicpu_sc[0];
629 	if (!sc)
630 		return 0;
631 	*pss = sc->sc_pss;
632 
633 	return (sc->sc_pss_len);
634 }
635 
636 int
637 acpicpu_notify(struct aml_node *node, int notify_type, void *arg)
638 {
639 	struct acpicpu_softc	*sc = arg;
640 
641 	dnprintf(10, "acpicpu_notify: %.2x %s\n", notify_type,
642 	    sc->sc_devnode->name);
643 
644 	switch (notify_type) {
645 	case 0x80:	/* _PPC changed, retrieve new values */
646 		acpicpu_getppc(sc);
647 		acpicpu_getpss(sc);
648 		if (sc->sc_notify)
649 			sc->sc_notify(sc->sc_pss, sc->sc_pss_len);
650 
651 		break;
652 	default:
653 		printf("%s: unhandled cpu event %x\n", DEVNAME(sc),
654 		    notify_type);
655 		break;
656 	}
657 
658 	return (0);
659 }
660 
661 void
662 acpicpu_set_notify(void (*func)(struct acpicpu_pss *, int))
663 {
664 	struct acpicpu_softc    *sc;
665 
666 	sc = acpicpu_sc[0];
667 	if (sc != NULL)
668 		sc->sc_notify = func;
669 }
670 
671 void
672 acpicpu_setperf_ppc_change(struct acpicpu_pss *pss, int npss)
673 {
674 	struct acpicpu_softc    *sc;
675 
676 	sc = acpicpu_sc[0];
677 
678 	if (sc != NULL)
679 		cpu_setperf(sc->sc_level);
680 }
681 
682 void
683 acpicpu_setperf(int level)
684 {
685 	struct acpicpu_softc	*sc;
686 	struct acpicpu_pss	*pss = NULL;
687 	int			idx, len;
688 	u_int32_t		status = 0;
689 
690 	sc = acpicpu_sc[cpu_number()];
691 
692 	dnprintf(10, "%s: acpicpu setperf level %d\n",
693 	    sc->sc_devnode->name, level);
694 
695 	if (level < 0 || level > 100) {
696 		dnprintf(10, "%s: acpicpu setperf illegal percentage\n",
697 		    sc->sc_devnode->name);
698 		return;
699 	}
700 
701 	/*
702 	 * XXX this should be handled more gracefully and it needs to also do
703 	 * the duty cycle method instead of pss exclusively
704 	 */
705 	if (sc->sc_flags & FLAGS_NOPSS || sc->sc_flags & FLAGS_NOPCT) {
706 		dnprintf(10, "%s: acpicpu no _PSS or _PCT\n",
707 		    sc->sc_devnode->name);
708 		return;
709 	}
710 
711 	if (sc->sc_ppc)
712 		len = sc->sc_ppc;
713 	else
714 		len = sc->sc_pss_len;
715 	idx = (len - 1) - (level / (100 / len));
716 	if (idx < 0)
717 		idx = 0;
718 
719 	if (sc->sc_ppc)
720 		idx += sc->sc_pss_len - sc->sc_ppc;
721 
722 	if (idx > sc->sc_pss_len)
723 		idx = sc->sc_pss_len - 1;
724 
725 	dnprintf(10, "%s: acpicpu setperf index %d pss_len %d ppc %d\n",
726 	    sc->sc_devnode->name, idx, sc->sc_pss_len, sc->sc_ppc);
727 
728 	pss = &sc->sc_pss[idx];
729 
730 #ifdef ACPI_DEBUG
731 	/* keep this for now since we will need this for debug in the field */
732 	printf("0 status: %x %llx %u %u ctrl: %x %llx %u %u\n",
733 	    sc->sc_pct.pct_status.grd_gas.address_space_id,
734 	    sc->sc_pct.pct_status.grd_gas.address,
735 	    sc->sc_pct_stat_as, sc->sc_pct_stat_len,
736 	    sc->sc_pct.pct_ctrl.grd_gas.address_space_id,
737 	    sc->sc_pct.pct_ctrl.grd_gas.address,
738 	    sc->sc_pct_ctrl_as, sc->sc_pct_ctrl_len);
739 #endif
740 	acpi_gasio(sc->sc_acpi, ACPI_IOREAD,
741 	    sc->sc_pct.pct_status.grd_gas.address_space_id,
742 	    sc->sc_pct.pct_status.grd_gas.address, sc->sc_pct_stat_as,
743 	    sc->sc_pct_stat_len, &status);
744 	dnprintf(20, "1 status: %u <- %u\n", status, pss->pss_status);
745 
746 	/* Are we already at the requested frequency? */
747 	if (status == pss->pss_status)
748 		return;
749 
750 	acpi_gasio(sc->sc_acpi, ACPI_IOWRITE,
751 	    sc->sc_pct.pct_ctrl.grd_gas.address_space_id,
752 	    sc->sc_pct.pct_ctrl.grd_gas.address, sc->sc_pct_ctrl_as,
753 	    sc->sc_pct_ctrl_len, &pss->pss_ctrl);
754 	dnprintf(20, "pss_ctrl: %x\n", pss->pss_ctrl);
755 
756 	acpi_gasio(sc->sc_acpi, ACPI_IOREAD,
757 	    sc->sc_pct.pct_status.grd_gas.address_space_id,
758 	    sc->sc_pct.pct_status.grd_gas.address, sc->sc_pct_stat_as,
759 	    sc->sc_pct_stat_as, &status);
760 	dnprintf(20, "2 status: %d\n", status);
761 
762 	/* Did the transition succeed? */
763 	 if (status == pss->pss_status) {
764 		cpuspeed = pss->pss_core_freq;
765 		sc->sc_level = level;
766 	} else
767 		printf("%s: acpicpu setperf failed to alter frequency\n",
768 		    sc->sc_devnode->name);
769 }
770