acpi_cpu_md.c revision 1.16 1 /* $NetBSD: acpi_cpu_md.c,v 1.16 2010/08/19 11:08:33 jmcneill Exp $ */
2
3 /*-
4 * Copyright (c) 2010 Jukka Ruohonen <jruohonen (at) iki.fi>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: acpi_cpu_md.c,v 1.16 2010/08/19 11:08:33 jmcneill Exp $");
31
32 #include <sys/param.h>
33 #include <sys/bus.h>
34 #include <sys/kcore.h>
35 #include <sys/sysctl.h>
36 #include <sys/xcall.h>
37
38 #include <x86/cpu.h>
39 #include <x86/cpufunc.h>
40 #include <x86/cputypes.h>
41 #include <x86/cpuvar.h>
42 #include <x86/cpu_msr.h>
43 #include <x86/machdep.h>
44
45 #include <dev/acpi/acpica.h>
46 #include <dev/acpi/acpi_cpu.h>
47
48 #include <dev/pci/pcivar.h>
49 #include <dev/pci/pcidevs.h>
50
51 static char native_idle_text[16];
52 void (*native_idle)(void) = NULL;
53 void (*native_cpu_freq_init)(int) = NULL;
54
55 static int acpicpu_md_quirks_piix4(struct pci_attach_args *);
56 static int acpicpu_md_pstate_sysctl_get(SYSCTLFN_PROTO);
57 static int acpicpu_md_pstate_sysctl_set(SYSCTLFN_PROTO);
58 static int acpicpu_md_pstate_sysctl_all(SYSCTLFN_PROTO);
59 static void acpicpu_md_pstate_status(void *, void *);
60 static void acpicpu_md_tstate_status(void *, void *);
61
62 extern uint32_t cpus_running;
63 extern struct acpicpu_softc **acpicpu_sc;
64
65 uint32_t
66 acpicpu_md_cap(void)
67 {
68 struct cpu_info *ci = curcpu();
69 uint32_t val = 0;
70
71 switch (cpu_vendor) {
72 case CPUVENDOR_INTEL:
73 case CPUVENDOR_IDT:
74 break;
75 default:
76 return val;
77 }
78
79 /*
80 * Basic SMP C-states (required for _CST).
81 */
82 val |= ACPICPU_PDC_C_C1PT | ACPICPU_PDC_C_C2C3;
83
84 /*
85 * If MONITOR/MWAIT is available, announce
86 * support for native instructions in all C-states.
87 */
88 if ((ci->ci_feat_val[1] & CPUID2_MONITOR) != 0)
89 val |= ACPICPU_PDC_C_C1_FFH | ACPICPU_PDC_C_C2C3_FFH;
90
91 /*
92 * Set native P- and T-states, if available.
93 */
94 if ((ci->ci_feat_val[1] & CPUID2_EST) != 0)
95 val |= ACPICPU_PDC_P_FFH;
96
97 if ((ci->ci_feat_val[0] & CPUID_ACPI) != 0)
98 val |= ACPICPU_PDC_T_FFH;
99
100 return val;
101 }
102
103 uint32_t
104 acpicpu_md_quirks(void)
105 {
106 struct cpu_info *ci = curcpu();
107 struct pci_attach_args pa;
108 uint32_t val = 0;
109
110 if (acpicpu_md_cpus_running() == 1)
111 val |= ACPICPU_FLAG_C_BM;
112
113 if ((ci->ci_feat_val[1] & CPUID2_MONITOR) != 0)
114 val |= ACPICPU_FLAG_C_FFH;
115
116 switch (cpu_vendor) {
117
118 case CPUVENDOR_INTEL:
119 case CPUVENDOR_IDT:
120 if ((ci->ci_feat_val[1] & CPUID2_EST) != 0)
121 val |= ACPICPU_FLAG_P_FFH;
122
123 if ((ci->ci_feat_val[0] & CPUID_ACPI) != 0)
124 val |= ACPICPU_FLAG_T_FFH;
125
126 val |= ACPICPU_FLAG_C_BM | ACPICPU_FLAG_C_ARB;
127
128 /*
129 * Bus master arbitration is not
130 * needed on some recent Intel CPUs.
131 */
132 if (cpu_vendor == CPUVENDOR_INTEL &&
133 CPUID2FAMILY(ci->ci_signature) > 15)
134 val &= ~ACPICPU_FLAG_C_ARB;
135
136 if (cpu_vendor == CPUVENDOR_INTEL &&
137 CPUID2FAMILY(ci->ci_signature) == 6 &&
138 CPUID2MODEL(ci->ci_signature) >= 15)
139 val &= ~ACPICPU_FLAG_C_ARB;
140
141 break;
142
143 case CPUVENDOR_AMD:
144
145 /*
146 * XXX: Deal with (non-XPSS) PowerNow! and C1E.
147 */
148 break;
149 }
150
151 /*
152 * There are several erratums for PIIX4.
153 */
154 if (pci_find_device(&pa, acpicpu_md_quirks_piix4) != 0)
155 val |= ACPICPU_FLAG_PIIX4;
156
157 return val;
158 }
159
160 static int
161 acpicpu_md_quirks_piix4(struct pci_attach_args *pa)
162 {
163
164 /*
165 * XXX: The pci_find_device(9) function only
166 * deals with attached devices. Change this
167 * to use something like pci_device_foreach().
168 */
169 if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_INTEL)
170 return 0;
171
172 if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_INTEL_82371AB_ISA ||
173 PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_INTEL_82440MX_PMC)
174 return 1;
175
176 return 0;
177 }
178
179 uint32_t
180 acpicpu_md_cpus_running(void)
181 {
182
183 return popcount32(cpus_running);
184 }
185
186 int
187 acpicpu_md_idle_start(void)
188 {
189 const size_t size = sizeof(native_idle_text);
190
191 x86_disable_intr();
192 x86_cpu_idle_get(&native_idle, native_idle_text, size);
193 x86_cpu_idle_set(acpicpu_cstate_idle, "acpi");
194 x86_enable_intr();
195
196 return 0;
197 }
198
199 int
200 acpicpu_md_idle_stop(void)
201 {
202 uint64_t xc;
203
204 x86_disable_intr();
205 x86_cpu_idle_set(native_idle, native_idle_text);
206 x86_enable_intr();
207
208 /*
209 * Run a cross-call to ensure that all CPUs are
210 * out from the ACPI idle-loop before detachment.
211 */
212 xc = xc_broadcast(0, (xcfunc_t)nullop, NULL, NULL);
213 xc_wait(xc);
214
215 return 0;
216 }
217
218 /*
219 * The MD idle loop. Called with interrupts disabled.
220 */
221 void
222 acpicpu_md_idle_enter(int method, int state)
223 {
224 struct cpu_info *ci = curcpu();
225
226 switch (method) {
227
228 case ACPICPU_C_STATE_FFH:
229
230 x86_enable_intr();
231 x86_monitor(&ci->ci_want_resched, 0, 0);
232
233 if (__predict_false(ci->ci_want_resched) != 0)
234 return;
235
236 x86_mwait((state - 1) << 4, 0);
237 break;
238
239 case ACPICPU_C_STATE_HALT:
240
241 if (__predict_false(ci->ci_want_resched) != 0) {
242 x86_enable_intr();
243 return;
244 }
245
246 x86_stihlt();
247 break;
248 }
249 }
250
251 int
252 acpicpu_md_pstate_start(void)
253 {
254 const struct sysctlnode *fnode, *mnode, *rnode;
255 const char *str;
256 int rv;
257
258 switch (cpu_vendor) {
259
260 case CPUVENDOR_INTEL:
261 case CPUVENDOR_IDT:
262 str = "est";
263 break;
264
265 case CPUVENDOR_AMD:
266 str = "powernow";
267 break;
268
269 default:
270 return ENODEV;
271 }
272
273 /*
274 * A kludge for backwards compatibility.
275 */
276 native_cpu_freq_init = cpu_freq_init;
277
278 if (cpu_freq_sysctllog != NULL) {
279 sysctl_teardown(&cpu_freq_sysctllog);
280 cpu_freq_sysctllog = NULL;
281 }
282
283 rv = sysctl_createv(&cpu_freq_sysctllog, 0, NULL, &rnode,
284 CTLFLAG_PERMANENT, CTLTYPE_NODE, "machdep", NULL,
285 NULL, 0, NULL, 0, CTL_MACHDEP, CTL_EOL);
286
287 if (rv != 0)
288 goto fail;
289
290 rv = sysctl_createv(&cpu_freq_sysctllog, 0, &rnode, &mnode,
291 0, CTLTYPE_NODE, str, NULL,
292 NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL);
293
294 if (rv != 0)
295 goto fail;
296
297 rv = sysctl_createv(&cpu_freq_sysctllog, 0, &mnode, &fnode,
298 0, CTLTYPE_NODE, "frequency", NULL,
299 NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL);
300
301 if (rv != 0)
302 goto fail;
303
304 rv = sysctl_createv(&cpu_freq_sysctllog, 0, &fnode, &rnode,
305 CTLFLAG_READWRITE, CTLTYPE_INT, "target", NULL,
306 acpicpu_md_pstate_sysctl_set, 0, NULL, 0, CTL_CREATE, CTL_EOL);
307
308 if (rv != 0)
309 goto fail;
310
311 rv = sysctl_createv(&cpu_freq_sysctllog, 0, &fnode, &rnode,
312 CTLFLAG_READONLY, CTLTYPE_INT, "current", NULL,
313 acpicpu_md_pstate_sysctl_get, 0, NULL, 0, CTL_CREATE, CTL_EOL);
314
315 if (rv != 0)
316 goto fail;
317
318 rv = sysctl_createv(&cpu_freq_sysctllog, 0, &fnode, &rnode,
319 CTLFLAG_READONLY, CTLTYPE_STRING, "available", NULL,
320 acpicpu_md_pstate_sysctl_all, 0, NULL, 0, CTL_CREATE, CTL_EOL);
321
322 if (rv != 0)
323 goto fail;
324
325 return 0;
326
327 fail:
328 if (cpu_freq_sysctllog != NULL) {
329 sysctl_teardown(&cpu_freq_sysctllog);
330 cpu_freq_sysctllog = NULL;
331 }
332
333 if (native_cpu_freq_init != NULL)
334 (*native_cpu_freq_init)(cpu_vendor);
335
336 return rv;
337 }
338
339 int
340 acpicpu_md_pstate_stop(void)
341 {
342
343 if (cpu_freq_sysctllog != NULL) {
344 sysctl_teardown(&cpu_freq_sysctllog);
345 cpu_freq_sysctllog = NULL;
346 }
347
348 if (native_cpu_freq_init != NULL)
349 (*native_cpu_freq_init)(cpu_vendor);
350
351 return 0;
352 }
353
354 static int
355 acpicpu_md_pstate_sysctl_get(SYSCTLFN_ARGS)
356 {
357 struct cpu_info *ci = curcpu();
358 struct acpicpu_softc *sc;
359 struct sysctlnode node;
360 uint32_t freq;
361 int err;
362
363 sc = acpicpu_sc[ci->ci_acpiid];
364
365 if (sc == NULL)
366 return ENXIO;
367
368 err = acpicpu_pstate_get(sc, &freq);
369
370 if (err != 0)
371 return err;
372
373 node = *rnode;
374 node.sysctl_data = &freq;
375
376 err = sysctl_lookup(SYSCTLFN_CALL(&node));
377
378 if (err != 0 || newp == NULL)
379 return err;
380
381 return 0;
382 }
383
384 static int
385 acpicpu_md_pstate_sysctl_set(SYSCTLFN_ARGS)
386 {
387 struct cpu_info *ci = curcpu();
388 struct acpicpu_softc *sc;
389 struct sysctlnode node;
390 uint32_t freq;
391 int err;
392
393 sc = acpicpu_sc[ci->ci_acpiid];
394
395 if (sc == NULL)
396 return ENXIO;
397
398 err = acpicpu_pstate_get(sc, &freq);
399
400 if (err != 0)
401 return err;
402
403 node = *rnode;
404 node.sysctl_data = &freq;
405
406 err = sysctl_lookup(SYSCTLFN_CALL(&node));
407
408 if (err != 0 || newp == NULL)
409 return err;
410
411 err = acpicpu_pstate_set(sc, freq);
412
413 if (err != 0)
414 return err;
415
416 return 0;
417 }
418
419 static int
420 acpicpu_md_pstate_sysctl_all(SYSCTLFN_ARGS)
421 {
422 struct cpu_info *ci = curcpu();
423 struct acpicpu_softc *sc;
424 struct sysctlnode node;
425 char buf[1024];
426 size_t len;
427 uint32_t i;
428 int err;
429
430 sc = acpicpu_sc[ci->ci_acpiid];
431
432 if (sc == NULL)
433 return ENXIO;
434
435 (void)memset(&buf, 0, sizeof(buf));
436
437 mutex_enter(&sc->sc_mtx);
438
439 for (len = 0, i = sc->sc_pstate_max; i < sc->sc_pstate_count; i++) {
440
441 if (sc->sc_pstate[i].ps_freq == 0)
442 continue;
443
444 len += snprintf(buf + len, sizeof(buf) - len, "%u%s",
445 sc->sc_pstate[i].ps_freq,
446 i < (sc->sc_pstate_count - 1) ? " " : "");
447 }
448
449 mutex_exit(&sc->sc_mtx);
450
451 node = *rnode;
452 node.sysctl_data = buf;
453
454 err = sysctl_lookup(SYSCTLFN_CALL(&node));
455
456 if (err != 0 || newp == NULL)
457 return err;
458
459 return 0;
460 }
461
462 int
463 acpicpu_md_pstate_pss(struct acpicpu_softc *sc)
464 {
465 struct acpicpu_pstate *ps, msr;
466 uint32_t i = 0;
467
468 (void)memset(&msr, 0, sizeof(struct acpicpu_pstate));
469
470 switch (cpu_vendor) {
471
472 case CPUVENDOR_INTEL:
473 case CPUVENDOR_IDT:
474 msr.ps_control_addr = MSR_PERF_CTL;
475 msr.ps_control_mask = __BITS(0, 15);
476
477 msr.ps_status_addr = MSR_PERF_STATUS;
478 msr.ps_status_mask = __BITS(0, 15);
479 break;
480
481 case CPUVENDOR_AMD:
482
483 if ((sc->sc_flags & ACPICPU_FLAG_P_XPSS) == 0)
484 return EOPNOTSUPP;
485
486 break;
487
488 default:
489 return ENODEV;
490 }
491
492 while (i < sc->sc_pstate_count) {
493
494 ps = &sc->sc_pstate[i];
495
496 if (ps->ps_status_addr == 0)
497 ps->ps_status_addr = msr.ps_status_addr;
498
499 if (ps->ps_status_mask == 0)
500 ps->ps_status_mask = msr.ps_status_mask;
501
502 if (ps->ps_control_addr == 0)
503 ps->ps_control_addr = msr.ps_control_addr;
504
505 if (ps->ps_control_mask == 0)
506 ps->ps_control_mask = msr.ps_control_mask;
507
508 i++;
509 }
510
511 return 0;
512 }
513
514 int
515 acpicpu_md_pstate_get(struct acpicpu_softc *sc, uint32_t *freq)
516 {
517 struct acpicpu_pstate *ps = NULL;
518 uint64_t val;
519 uint32_t i;
520
521 for (i = 0; i < sc->sc_pstate_count; i++) {
522
523 ps = &sc->sc_pstate[i];
524
525 if (ps->ps_freq != 0)
526 break;
527 }
528
529 if (__predict_false(ps == NULL))
530 return EINVAL;
531
532 if (ps->ps_status_addr == 0)
533 return EINVAL;
534
535 val = rdmsr(ps->ps_status_addr);
536
537 if (ps->ps_status_mask != 0)
538 val = val & ps->ps_status_mask;
539
540 for (i = 0; i < sc->sc_pstate_count; i++) {
541
542 ps = &sc->sc_pstate[i];
543
544 if (ps->ps_freq == 0)
545 continue;
546
547 if (val == ps->ps_status) {
548 *freq = ps->ps_freq;
549 return 0;
550 }
551 }
552
553 return EIO;
554 }
555
556 int
557 acpicpu_md_pstate_set(struct acpicpu_pstate *ps)
558 {
559 struct msr_rw_info msr;
560 uint64_t xc;
561 int rv = 0;
562
563 msr.msr_read = false;
564 msr.msr_type = ps->ps_control_addr;
565 msr.msr_value = ps->ps_control;
566
567 if (ps->ps_control_mask != 0) {
568 msr.msr_mask = ps->ps_control_mask;
569 msr.msr_read = true;
570 }
571
572 xc = xc_broadcast(0, (xcfunc_t)x86_msr_xcall, &msr, NULL);
573 xc_wait(xc);
574
575 if (ps->ps_status_addr == 0)
576 return 0;
577
578 xc = xc_broadcast(0, (xcfunc_t)acpicpu_md_pstate_status, ps, &rv);
579 xc_wait(xc);
580
581 return rv;
582 }
583
584 static void
585 acpicpu_md_pstate_status(void *arg1, void *arg2)
586 {
587 struct acpicpu_pstate *ps = arg1;
588 uint64_t val;
589 int i;
590
591 for (i = val = 0; i < ACPICPU_P_STATE_RETRY; i++) {
592
593 val = rdmsr(ps->ps_status_addr);
594
595 if (ps->ps_status_mask != 0)
596 val = val & ps->ps_status_mask;
597
598 if (val == ps->ps_status)
599 return;
600
601 DELAY(ps->ps_latency);
602 }
603
604 *(uintptr_t *)arg2 = EAGAIN;
605 }
606
607 int
608 acpicpu_md_tstate_get(struct acpicpu_softc *sc, uint32_t *percent)
609 {
610 struct acpicpu_tstate *ts;
611 uint64_t val;
612 uint32_t i;
613
614 if (cpu_vendor != CPUVENDOR_INTEL &&
615 cpu_vendor != CPUVENDOR_IDT)
616 return ENODEV;
617
618 val = rdmsr(MSR_THERM_CONTROL);
619
620 for (i = 0; i < sc->sc_tstate_count; i++) {
621
622 ts = &sc->sc_tstate[i];
623
624 if (ts->ts_percent == 0)
625 continue;
626
627 if (val == ts->ts_control || val == ts->ts_status) {
628 *percent = ts->ts_percent;
629 return 0;
630 }
631 }
632
633 return EIO;
634 }
635
636 int
637 acpicpu_md_tstate_set(struct acpicpu_tstate *ts)
638 {
639 struct msr_rw_info msr;
640 uint64_t xc;
641 int rv = 0;
642
643 if (cpu_vendor != CPUVENDOR_INTEL &&
644 cpu_vendor != CPUVENDOR_IDT)
645 return ENODEV;
646
647 msr.msr_read = true;
648 msr.msr_type = MSR_THERM_CONTROL;
649 msr.msr_value = ts->ts_control;
650 msr.msr_mask = __BITS(1, 4);
651
652 xc = xc_broadcast(0, (xcfunc_t)x86_msr_xcall, &msr, NULL);
653 xc_wait(xc);
654
655 if (ts->ts_status == 0)
656 return 0;
657
658 xc = xc_broadcast(0, (xcfunc_t)acpicpu_md_tstate_status, ts, &rv);
659 xc_wait(xc);
660
661 return rv;
662 }
663
664 static void
665 acpicpu_md_tstate_status(void *arg1, void *arg2)
666 {
667 struct acpicpu_tstate *ts = arg1;
668 uint64_t val;
669 int i;
670
671 for (i = val = 0; i < ACPICPU_T_STATE_RETRY; i++) {
672
673 val = rdmsr(MSR_THERM_CONTROL);
674
675 if (val == ts->ts_status)
676 return;
677
678 DELAY(ts->ts_latency);
679 }
680
681 *(uintptr_t *)arg2 = EAGAIN;
682 }
683