This source file includes following definitions.
- acpicpu_set_throttle
- acpicpu_find_cstate
- acpicpu_add_cstate
- acpicpu_add_cstatepkg
- acpicpu_match
- acpicpu_attach
- acpicpu_getpct
- acpicpu_getpss
- acpicpu_fetch_pss
- acpicpu_notify
- acpicpu_set_notify
- acpicpu_setperf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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
45 #define ACPI_STATE_C0 0x00
46 #define ACPI_STATE_C1 0x01
47 #define ACPI_STATE_C2 0x02
48 #define ACPI_STATE_C3 0x03
49
50 #define FLAGS_NO_C2 0x01
51 #define FLAGS_NO_C3 0x02
52 #define FLAGS_BMCHECK 0x04
53 #define FLAGS_NOTHROTTLE 0x08
54 #define FLAGS_NOPSS 0x10
55 #define FLAGS_NOPCT 0x20
56
57 #define CPU_THT_EN (1L << 4)
58 #define CPU_MAXSTATE(sc) (1L << (sc)->sc_duty_wid)
59 #define CPU_STATE(sc,pct) ((pct * CPU_MAXSTATE(sc) / 100) << (sc)->sc_duty_off)
60 #define CPU_STATEMASK(sc) ((CPU_MAXSTATE(sc) - 1) << (sc)->sc_duty_off)
61
62 #define ACPI_MAX_C2_LATENCY 100
63 #define ACPI_MAX_C3_LATENCY 1000
64
65
66 #define valid_throttle(o,w,a) (a && w && (o+w)<=31 && (o>4 || (o+w)<=4))
67
68 struct acpi_cstate
69 {
70 int type;
71 int latency;
72 int power;
73 int address;
74
75 SLIST_ENTRY(acpi_cstate) link;
76 };
77
78 struct acpicpu_softc {
79 struct device sc_dev;
80 int sc_cpu;
81
82 int sc_duty_wid;
83 int sc_duty_off;
84 int sc_pblk_addr;
85 int sc_pblk_len;
86 int sc_flags;
87
88 SLIST_HEAD(,acpi_cstate) sc_cstates;
89
90 bus_space_tag_t sc_iot;
91 bus_space_handle_t sc_ioh;
92
93 struct acpi_softc *sc_acpi;
94 struct aml_node *sc_devnode;
95
96 int sc_pss_len;
97 struct acpicpu_pss *sc_pss;
98
99 struct acpicpu_pct sc_pct;
100
101
102
103
104
105
106 void (*sc_notify)(struct acpicpu_pss *, int);
107 };
108
109 void acpicpu_set_throttle(struct acpicpu_softc *, int);
110 void acpicpu_add_cstatepkg(struct aml_value *, void *);
111 int acpicpu_getpct(struct acpicpu_softc *);
112 int acpicpu_getpss(struct acpicpu_softc *);
113 struct acpi_cstate *acpicpu_add_cstate(struct acpicpu_softc *, int, int, int, int);
114 struct acpi_cstate *acpicpu_find_cstate(struct acpicpu_softc *, int);
115
116 struct cfattach acpicpu_ca = {
117 sizeof(struct acpicpu_softc), acpicpu_match, acpicpu_attach
118 };
119
120 struct cfdriver acpicpu_cd = {
121 NULL, "acpicpu", DV_DULL
122 };
123
124 extern int setperf_prio;
125
126 #ifdef __i386__
127 struct acpicpu_softc *acpicpu_sc[I386_MAXPROCS];
128 #elif __amd64__
129 struct acpicpu_softc *acpicpu_sc[X86_MAXPROCS];
130 #endif
131
132 void
133 acpicpu_set_throttle(struct acpicpu_softc *sc, int level)
134 {
135 uint32_t pbval;
136
137 if (sc->sc_flags & FLAGS_NOTHROTTLE)
138 return;
139
140
141 pbval = inl(sc->sc_pblk_addr);
142 outl(sc->sc_pblk_addr, pbval & ~CPU_THT_EN);
143 if (level < 100) {
144 pbval &= ~CPU_STATEMASK(sc);
145 pbval |= CPU_STATE(sc, level);
146 outl(sc->sc_pblk_addr, pbval & ~CPU_THT_EN);
147 outl(sc->sc_pblk_addr, pbval | CPU_THT_EN);
148 }
149 }
150
151 struct acpi_cstate *
152 acpicpu_find_cstate(struct acpicpu_softc *sc, int type)
153 {
154 struct acpi_cstate *cx;
155
156 SLIST_FOREACH(cx, &sc->sc_cstates, link)
157 if (cx->type == type)
158 return cx;
159 return NULL;
160 }
161
162 struct acpi_cstate *
163 acpicpu_add_cstate(struct acpicpu_softc *sc, int type,
164 int latency, int power, int address)
165 {
166 struct acpi_cstate *cx;
167
168 dnprintf(10," C%d: latency:.%4x power:%.4x addr:%.8x\n",
169 type, latency, power, address);
170
171 switch (type) {
172 case ACPI_STATE_C2:
173 if (latency > ACPI_MAX_C2_LATENCY || !address ||
174 (sc->sc_flags & FLAGS_NO_C2))
175 goto bad;
176 break;
177 case ACPI_STATE_C3:
178 if (latency > ACPI_MAX_C3_LATENCY || !address ||
179 (sc->sc_flags & FLAGS_NO_C3))
180 goto bad;
181 break;
182 }
183
184 cx = malloc(sizeof(struct acpi_cstate), M_DEVBUF, M_WAITOK);
185 memset(cx, 0, sizeof(struct acpi_cstate));
186
187 cx->type = type;
188 cx->power = power;
189 cx->latency = latency;
190 cx->address = address;
191
192 SLIST_INSERT_HEAD(&sc->sc_cstates, cx, link);
193
194 return cx;
195 bad:
196 dprintf("acpicpu%d: C%d not supported", sc->sc_cpu, type);
197 return NULL;
198 }
199
200
201 void
202 acpicpu_add_cstatepkg(struct aml_value *val, void *arg)
203 {
204 struct acpicpu_softc *sc = arg;
205
206 #ifdef ACPI_DEBUG
207 aml_showvalue(val, 0);
208 #endif
209 if (val->type != AML_OBJTYPE_PACKAGE || val->length != 4)
210 return;
211 acpicpu_add_cstate(sc, val->v_package[1]->v_integer,
212 val->v_package[2]->v_integer,
213 val->v_package[3]->v_integer,
214 -1);
215 }
216
217
218 int
219 acpicpu_match(struct device *parent, void *match, void *aux)
220 {
221 struct acpi_attach_args *aa = aux;
222 struct cfdata *cf = match;
223
224
225 if (aa->aaa_name == NULL ||
226 strcmp(aa->aaa_name, cf->cf_driver->cd_name) != 0 ||
227 aa->aaa_table != NULL)
228 return (0);
229
230 return (1);
231 }
232
233 void
234 acpicpu_attach(struct device *parent, struct device *self, void *aux)
235 {
236 struct acpicpu_softc *sc = (struct acpicpu_softc *)self;
237 struct acpi_attach_args *aa = aux;
238 struct aml_value res;
239 int i;
240 struct acpi_cstate *cx;
241
242 sc->sc_acpi = (struct acpi_softc *)parent;
243 sc->sc_devnode = aa->aaa_node;
244 acpicpu_sc[sc->sc_dev.dv_unit] = sc;
245
246 SLIST_INIT(&sc->sc_cstates);
247
248 sc->sc_pss = NULL;
249
250 if (aml_evalnode(sc->sc_acpi, sc->sc_devnode, 0, NULL, &res) == 0) {
251 if (res.type == AML_OBJTYPE_PROCESSOR) {
252 sc->sc_cpu = res.v_processor.proc_id;
253 sc->sc_pblk_addr = res.v_processor.proc_addr;
254 sc->sc_pblk_len = res.v_processor.proc_len;
255 }
256 aml_freevalue(&res);
257 }
258 sc->sc_duty_off = sc->sc_acpi->sc_fadt->duty_offset;
259 sc->sc_duty_wid = sc->sc_acpi->sc_fadt->duty_width;
260 if (!valid_throttle(sc->sc_duty_off, sc->sc_duty_wid, sc->sc_pblk_addr))
261 sc->sc_flags |= FLAGS_NOTHROTTLE;
262
263 #ifdef ACPI_DEBUG
264 printf(": %s: ", sc->sc_devnode->name);
265 printf("\n: hdr:%x pblk:%x,%x duty:%x,%x pstate:%x (%d throttling states)\n",
266 sc->sc_acpi->sc_fadt->hdr_revision,
267 sc->sc_pblk_addr, sc->sc_pblk_len,
268 sc->sc_duty_off, sc->sc_duty_wid,
269 sc->sc_acpi->sc_fadt->pstate_cnt,
270 CPU_MAXSTATE(sc));
271 #endif
272
273
274 if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_CST", 0, NULL, &res) == 0) {
275 aml_foreachpkg(&res, 1, acpicpu_add_cstatepkg, sc);
276 aml_freevalue(&res);
277 }
278 else {
279
280 if (sc->sc_pblk_len < 5)
281 sc->sc_flags |= FLAGS_NO_C2;
282 if (sc->sc_pblk_len < 6)
283 sc->sc_flags |= FLAGS_NO_C3;
284 acpicpu_add_cstate(sc, ACPI_STATE_C2,
285 sc->sc_acpi->sc_fadt->p_lvl2_lat, -1,
286 sc->sc_pblk_addr + 4);
287 acpicpu_add_cstate(sc, ACPI_STATE_C3,
288 sc->sc_acpi->sc_fadt->p_lvl3_lat, -1,
289 sc->sc_pblk_addr + 5);
290 }
291 if (acpicpu_getpss(sc)) {
292
293 sc->sc_flags |= FLAGS_NOPSS;
294 } else {
295
296 #ifdef ACPI_DEBUG
297 for (i = 0; i < sc->sc_pss_len; i++) {
298 dnprintf(20, "%d %d %d %d %d %d\n",
299 sc->sc_pss[i].pss_core_freq,
300 sc->sc_pss[i].pss_power,
301 sc->sc_pss[i].pss_trans_latency,
302 sc->sc_pss[i].pss_bus_latency,
303 sc->sc_pss[i].pss_ctrl,
304 sc->sc_pss[i].pss_status);
305 }
306 dnprintf(20, "\n");
307 #endif
308
309 if (acpicpu_getpct(sc))
310 sc->sc_flags |= FLAGS_NOPCT;
311 else {
312
313
314 if (sc->sc_acpi->sc_fadt->pstate_cnt)
315 acpi_write_pmreg(sc->sc_acpi, ACPIREG_SMICMD, 0,
316 sc->sc_acpi->sc_fadt->pstate_cnt);
317
318 aml_register_notify(sc->sc_devnode, NULL,
319 acpicpu_notify, sc, ACPIDEV_NOPOLL);
320
321 if (setperf_prio < 30) {
322 cpu_setperf = acpicpu_setperf;
323 setperf_prio = 30;
324 acpi_hasprocfvs = 1;
325 }
326 }
327 }
328
329
330
331
332
333 i = 0;
334 SLIST_FOREACH(cx, &sc->sc_cstates, link) {
335 if (i)
336 printf(",");
337 switch(cx->type) {
338 case ACPI_STATE_C0:
339 printf(" C0");
340 break;
341 case ACPI_STATE_C1:
342 printf(" C1");
343 break;
344 case ACPI_STATE_C2:
345 printf(" C2");
346 break;
347 case ACPI_STATE_C3:
348 printf(" C3");
349 break;
350 }
351 i++;
352 }
353 if (!(sc->sc_flags & FLAGS_NOPSS) && !(sc->sc_flags & FLAGS_NOPCT)) {
354 if (i)
355 printf(",");
356 printf(" FVS");
357 } else if (!(sc->sc_flags & FLAGS_NOPSS)) {
358 if (i)
359 printf(",");
360 printf(" PSS");
361 }
362 printf("\n");
363
364
365
366
367
368
369 if (!(sc->sc_flags & FLAGS_NOPSS) && !(sc->sc_flags & FLAGS_NOPCT)) {
370 printf("%s: ", sc->sc_dev.dv_xname);
371 for (i = 0; i < sc->sc_pss_len; i++)
372 printf("%d%s", sc->sc_pss[i].pss_core_freq,
373 i < sc->sc_pss_len - 1 ? ", " : " MHz\n");
374 }
375 }
376
377 int
378 acpicpu_getpct(struct acpicpu_softc *sc)
379 {
380 struct aml_value res;
381 int rv = 1;
382
383 if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_PPC", 0, NULL, &res)) {
384 dnprintf(20, "%s: no _PPC\n", DEVNAME(sc));
385 dnprintf(10, "%s: no _PPC\n", DEVNAME(sc));
386 return (1);
387 }
388
389 dnprintf(10, "_PPC: %d\n", aml_val2int(&res));
390 aml_freevalue(&res);
391
392 if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_PCT", 0, NULL, &res)) {
393 dnprintf(20, "%s: no _PCT\n", DEVNAME(sc));
394 return (1);
395 }
396
397 if (res.length != 2) {
398 dnprintf(20, "%s: %s: invalid _PCT length\n", DEVNAME(sc),
399 sc->sc_devnode->name);
400 return (1);
401 }
402
403 memcpy(&sc->sc_pct.pct_ctrl, res.v_package[0]->v_buffer,
404 sizeof sc->sc_pct.pct_ctrl);
405 if (sc->sc_pct.pct_ctrl.grd_gas.address_space_id ==
406 GAS_FUNCTIONAL_FIXED) {
407 dnprintf(20, "CTRL GASIO is functional fixed hardware.\n");
408 goto ffh;
409 }
410
411 memcpy(&sc->sc_pct.pct_status, res.v_package[1]->v_buffer,
412 sizeof sc->sc_pct.pct_status);
413 if (sc->sc_pct.pct_status.grd_gas.address_space_id ==
414 GAS_FUNCTIONAL_FIXED) {
415 dnprintf(20, "CTRL GASIO is functional fixed hardware.\n");
416 goto ffh;
417 }
418
419 dnprintf(10, "_PCT(ctrl) : %02x %04x %02x %02x %02x %02x %016x\n",
420 sc->sc_pct.pct_ctrl.grd_descriptor,
421 sc->sc_pct.pct_ctrl.grd_length,
422 sc->sc_pct.pct_ctrl.grd_gas.address_space_id,
423 sc->sc_pct.pct_ctrl.grd_gas.register_bit_width,
424 sc->sc_pct.pct_ctrl.grd_gas.register_bit_offset,
425 sc->sc_pct.pct_ctrl.grd_gas.access_size,
426 sc->sc_pct.pct_ctrl.grd_gas.address);
427
428 dnprintf(10, "_PCT(status): %02x %04x %02x %02x %02x %02x %016x\n",
429 sc->sc_pct.pct_status.grd_descriptor,
430 sc->sc_pct.pct_status.grd_length,
431 sc->sc_pct.pct_status.grd_gas.address_space_id,
432 sc->sc_pct.pct_status.grd_gas.register_bit_width,
433 sc->sc_pct.pct_status.grd_gas.register_bit_offset,
434 sc->sc_pct.pct_status.grd_gas.access_size,
435 sc->sc_pct.pct_status.grd_gas.address);
436
437 rv = 0;
438 ffh:
439 aml_freevalue(&res);
440 return (rv);
441 }
442
443 int
444 acpicpu_getpss(struct acpicpu_softc *sc)
445 {
446 struct aml_value res;
447 int i;
448
449 if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_PSS", 0, NULL, &res)) {
450 dprintf("%s: no _PSS\n", DEVNAME(sc));
451 return (1);
452 }
453
454 if (sc->sc_pss)
455 free(sc->sc_pss, M_DEVBUF);
456
457 sc->sc_pss = malloc(res.length * sizeof *sc->sc_pss, M_DEVBUF,
458 M_WAITOK);
459
460 memset(sc->sc_pss, 0, res.length * sizeof *sc->sc_pss);
461
462 for (i = 0; i < res.length; i++) {
463 sc->sc_pss[i].pss_core_freq = aml_val2int(
464 res.v_package[i]->v_package[0]);
465 sc->sc_pss[i].pss_power = aml_val2int(
466 res.v_package[i]->v_package[1]);
467 sc->sc_pss[i].pss_trans_latency = aml_val2int(
468 res.v_package[i]->v_package[2]);
469 sc->sc_pss[i].pss_bus_latency = aml_val2int(
470 res.v_package[i]->v_package[3]);
471 sc->sc_pss[i].pss_ctrl = aml_val2int(
472 res.v_package[i]->v_package[4]);
473 sc->sc_pss[i].pss_status = aml_val2int(
474 res.v_package[i]->v_package[5]);
475 }
476 aml_freevalue(&res);
477
478 sc->sc_pss_len = res.length;
479
480 return (0);
481 }
482
483 int
484 acpicpu_fetch_pss(struct acpicpu_pss **pss) {
485
486
487
488
489 struct acpicpu_softc *sc;
490
491 sc = acpicpu_sc[0];
492 if (!sc) {
493 printf("couldnt fetch acpicpu_softc\n");
494 return 0;
495 }
496 *pss = sc->sc_pss;
497
498 return sc->sc_pss_len;
499 }
500
501 int
502 acpicpu_notify(struct aml_node *node, int notify_type, void *arg)
503 {
504 struct acpicpu_softc *sc = arg;
505
506 dnprintf(10, "acpicpu_notify: %.2x %s\n", notify_type,
507 sc->sc_devnode->name);
508
509 switch (notify_type) {
510 case 0x80:
511 acpicpu_getpct(sc);
512 acpicpu_getpss(sc);
513 if (sc->sc_notify)
514 sc->sc_notify(sc->sc_pss, sc->sc_pss_len);
515 break;
516 default:
517 printf("%s: unhandled cpu event %x\n", DEVNAME(sc),
518 notify_type);
519 break;
520 }
521
522 return (0);
523 }
524
525 void
526 acpicpu_set_notify(void (*func)(struct acpicpu_pss *, int)) {
527 struct acpicpu_softc *sc;
528
529 sc = acpicpu_sc[0];
530 if (sc != NULL)
531 sc->sc_notify = func;
532 }
533
534 void
535 acpicpu_setperf(int level) {
536 struct acpicpu_softc *sc;
537 struct acpicpu_pss *pss = NULL;
538 int idx;
539 u_int32_t stat_as, ctrl_as, stat_len, ctrl_len;
540 u_int32_t status = 0;
541
542 sc = acpicpu_sc[cpu_number()];
543
544 dnprintf(10, "%s: acpicpu setperf level %d\n",
545 sc->sc_devnode->name, level);
546
547 if (level < 0 || level > 100) {
548 dnprintf(10, "%s: acpicpu setperf illegal percentage\n",
549 sc->sc_devnode->name);
550 return;
551 }
552
553 idx = (sc->sc_pss_len - 1) - (level / (100 / sc->sc_pss_len));
554 if (idx < 0)
555 idx = 0;
556 if (idx > sc->sc_pss_len) {
557
558 printf("%s: acpicpu setperf index out of range\n",
559 sc->sc_devnode->name);
560 return;
561 }
562
563 dnprintf(10, "%s: acpicpu setperf index %d\n",
564 sc->sc_devnode->name, idx);
565
566 pss = &sc->sc_pss[idx];
567
568
569 stat_as = sc->sc_pct.pct_status.grd_gas.register_bit_width / 8;
570 if (stat_as == 0)
571 stat_as = 4;
572 ctrl_as = sc->sc_pct.pct_ctrl.grd_gas.register_bit_width / 8;
573 if (ctrl_as == 0)
574 ctrl_as = 4;
575 stat_len = sc->sc_pct.pct_status.grd_gas.access_size;
576 if (stat_len == 0)
577 stat_len = stat_as;
578 ctrl_len = sc->sc_pct.pct_ctrl.grd_gas.access_size;
579 if (ctrl_len == 0)
580 ctrl_len = ctrl_as;
581
582 #ifdef ACPI_DEBUG
583
584 printf("0 status: %x %llx %u %u ctrl: %x %llx %u %u\n",
585 sc->sc_pct.pct_status.grd_gas.address_space_id,
586 sc->sc_pct.pct_status.grd_gas.address,
587 stat_as, stat_len,
588 sc->sc_pct.pct_ctrl.grd_gas.address_space_id,
589 sc->sc_pct.pct_ctrl.grd_gas.address,
590 ctrl_as, ctrl_len);
591 #endif
592 acpi_gasio(sc->sc_acpi, ACPI_IOREAD,
593 sc->sc_pct.pct_status.grd_gas.address_space_id,
594 sc->sc_pct.pct_status.grd_gas.address, stat_as, stat_len,
595 &status);
596 dnprintf(20, "status: %u <- %u\n", status, pss->pss_status);
597
598
599 if (status == pss->pss_status)
600 return;
601
602 acpi_gasio(sc->sc_acpi, ACPI_IOWRITE,
603 sc->sc_pct.pct_ctrl.grd_gas.address_space_id,
604 sc->sc_pct.pct_ctrl.grd_gas.address, ctrl_as, ctrl_len,
605 &pss->pss_ctrl);
606 dnprintf(20, "pss_ctrl: %x\n", pss->pss_ctrl);
607
608 acpi_gasio(sc->sc_acpi, ACPI_IOREAD,
609 sc->sc_pct.pct_status.grd_gas.address_space_id,
610 sc->sc_pct.pct_status.grd_gas.address, stat_as, stat_as,
611 &status);
612 dnprintf(20, "3 status: %d\n", status);
613
614
615 if (status == pss->pss_status)
616 cpuspeed = pss->pss_core_freq;
617 else
618 printf("%s: acpicpu setperf failed to alter frequency\n",
619 sc->sc_devnode->name);
620 }