acpi_cpu_md.c revision 1.13 1 /* $NetBSD: acpi_cpu_md.c,v 1.13 2010/08/18 04:12:29 jruoho 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.13 2010/08/18 04:12:29 jruoho 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
60 extern uint32_t cpus_running;
61 extern struct acpicpu_softc **acpicpu_sc;
62
63 uint32_t
64 acpicpu_md_cap(void)
65 {
66 struct cpu_info *ci = curcpu();
67 uint32_t val = 0;
68
69 if (cpu_vendor != CPUVENDOR_INTEL)
70 return val;
71
72 /*
73 * Basic SMP C-states (required for _CST).
74 */
75 val |= ACPICPU_PDC_C_C1PT | ACPICPU_PDC_C_C2C3;
76
77 /*
78 * If MONITOR/MWAIT is available, announce
79 * support for native instructions in all C-states.
80 */
81 if ((ci->ci_feat_val[1] & CPUID2_MONITOR) != 0)
82 val |= ACPICPU_PDC_C_C1_FFH | ACPICPU_PDC_C_C2C3_FFH;
83
84 /*
85 * Set native P- and T-states, if available.
86 */
87 if ((ci->ci_feat_val[1] & CPUID2_EST) != 0)
88 val |= ACPICPU_PDC_P_FFH;
89
90 if ((ci->ci_feat_val[0] & CPUID_ACPI) != 0)
91 val |= ACPICPU_PDC_T_FFH;
92
93 return val;
94 }
95
96 uint32_t
97 acpicpu_md_quirks(void)
98 {
99 struct cpu_info *ci = curcpu();
100 struct pci_attach_args pa;
101 uint32_t val = 0;
102
103 if (acpicpu_md_cpus_running() == 1)
104 val |= ACPICPU_FLAG_C_BM;
105
106 if ((ci->ci_feat_val[1] & CPUID2_MONITOR) != 0)
107 val |= ACPICPU_FLAG_C_FFH;
108
109 switch (cpu_vendor) {
110
111 case CPUVENDOR_INTEL:
112
113 if ((ci->ci_feat_val[1] & CPUID2_EST) != 0)
114 val |= ACPICPU_FLAG_P_FFH;
115
116 if ((ci->ci_feat_val[0] & CPUID_ACPI) != 0)
117 val |= ACPICPU_FLAG_T_FFH;
118
119 val |= ACPICPU_FLAG_C_BM | ACPICPU_FLAG_C_ARB;
120
121 /*
122 * Bus master arbitration is not
123 * needed on some recent Intel CPUs.
124 */
125 if (CPUID2FAMILY(ci->ci_signature) > 15)
126 val &= ~ACPICPU_FLAG_C_ARB;
127
128 if (CPUID2FAMILY(ci->ci_signature) == 6 &&
129 CPUID2MODEL(ci->ci_signature) >= 15)
130 val &= ~ACPICPU_FLAG_C_ARB;
131
132 break;
133
134 case CPUVENDOR_AMD:
135
136 /*
137 * XXX: Deal with (non-XPSS) PowerNow! and C1E.
138 */
139 break;
140 }
141
142 /*
143 * There are several erratums for PIIX4.
144 */
145 if (pci_find_device(&pa, acpicpu_md_quirks_piix4) != 0)
146 val |= ACPICPU_FLAG_PIIX4;
147
148 return val;
149 }
150
151 static int
152 acpicpu_md_quirks_piix4(struct pci_attach_args *pa)
153 {
154
155 /*
156 * XXX: The pci_find_device(9) function only
157 * deals with attached devices. Change this
158 * to use something like pci_device_foreach().
159 */
160 if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_INTEL)
161 return 0;
162
163 if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_INTEL_82371AB_ISA ||
164 PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_INTEL_82440MX_PMC)
165 return 1;
166
167 return 0;
168 }
169
170 uint32_t
171 acpicpu_md_cpus_running(void)
172 {
173
174 return popcount32(cpus_running);
175 }
176
177 int
178 acpicpu_md_idle_start(void)
179 {
180 const size_t size = sizeof(native_idle_text);
181
182 x86_disable_intr();
183 x86_cpu_idle_get(&native_idle, native_idle_text, size);
184 x86_cpu_idle_set(acpicpu_cstate_idle, "acpi");
185 x86_enable_intr();
186
187 return 0;
188 }
189
190 int
191 acpicpu_md_idle_stop(void)
192 {
193 uint64_t xc;
194
195 x86_disable_intr();
196 x86_cpu_idle_set(native_idle, native_idle_text);
197 x86_enable_intr();
198
199 /*
200 * Run a cross-call to ensure that all CPUs are
201 * out from the ACPI idle-loop before detachment.
202 */
203 xc = xc_broadcast(0, (xcfunc_t)nullop, NULL, NULL);
204 xc_wait(xc);
205
206 return 0;
207 }
208
209 /*
210 * The MD idle loop. Called with interrupts disabled.
211 */
212 void
213 acpicpu_md_idle_enter(int method, int state)
214 {
215 struct cpu_info *ci = curcpu();
216
217 switch (method) {
218
219 case ACPICPU_C_STATE_FFH:
220
221 x86_enable_intr();
222 x86_monitor(&ci->ci_want_resched, 0, 0);
223
224 if (__predict_false(ci->ci_want_resched) != 0)
225 return;
226
227 x86_mwait((state - 1) << 4, 0);
228 break;
229
230 case ACPICPU_C_STATE_HALT:
231
232 if (__predict_false(ci->ci_want_resched) != 0) {
233 x86_enable_intr();
234 return;
235 }
236
237 x86_stihlt();
238 break;
239 }
240 }
241
242 int
243 acpicpu_md_pstate_start(void)
244 {
245 const struct sysctlnode *fnode, *mnode, *rnode;
246 const char *str;
247 int rv;
248
249 switch (cpu_vendor) {
250
251 case CPUVENDOR_INTEL:
252 str = "est";
253 break;
254
255 case CPUVENDOR_AMD:
256 str = "powernow";
257 break;
258
259 default:
260 return ENODEV;
261 }
262
263 /*
264 * A kludge for backwards compatibility.
265 */
266 native_cpu_freq_init = cpu_freq_init;
267
268 if (cpu_freq_sysctllog != NULL) {
269 sysctl_teardown(&cpu_freq_sysctllog);
270 cpu_freq_sysctllog = NULL;
271 }
272
273 rv = sysctl_createv(&cpu_freq_sysctllog, 0, NULL, &rnode,
274 CTLFLAG_PERMANENT, CTLTYPE_NODE, "machdep", NULL,
275 NULL, 0, NULL, 0, CTL_MACHDEP, CTL_EOL);
276
277 if (rv != 0)
278 goto fail;
279
280 rv = sysctl_createv(&cpu_freq_sysctllog, 0, &rnode, &mnode,
281 0, CTLTYPE_NODE, str, NULL,
282 NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL);
283
284 if (rv != 0)
285 goto fail;
286
287 rv = sysctl_createv(&cpu_freq_sysctllog, 0, &mnode, &fnode,
288 0, CTLTYPE_NODE, "frequency", NULL,
289 NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL);
290
291 if (rv != 0)
292 goto fail;
293
294 rv = sysctl_createv(&cpu_freq_sysctllog, 0, &fnode, &rnode,
295 CTLFLAG_READWRITE, CTLTYPE_INT, "target", NULL,
296 acpicpu_md_pstate_sysctl_set, 0, NULL, 0, CTL_CREATE, CTL_EOL);
297
298 if (rv != 0)
299 goto fail;
300
301 rv = sysctl_createv(&cpu_freq_sysctllog, 0, &fnode, &rnode,
302 CTLFLAG_READONLY, CTLTYPE_INT, "current", NULL,
303 acpicpu_md_pstate_sysctl_get, 0, NULL, 0, CTL_CREATE, CTL_EOL);
304
305 if (rv != 0)
306 goto fail;
307
308 rv = sysctl_createv(&cpu_freq_sysctllog, 0, &fnode, &rnode,
309 CTLFLAG_READONLY, CTLTYPE_STRING, "available", NULL,
310 acpicpu_md_pstate_sysctl_all, 0, NULL, 0, CTL_CREATE, CTL_EOL);
311
312 if (rv != 0)
313 goto fail;
314
315 return 0;
316
317 fail:
318 if (cpu_freq_sysctllog != NULL) {
319 sysctl_teardown(&cpu_freq_sysctllog);
320 cpu_freq_sysctllog = NULL;
321 }
322
323 if (native_cpu_freq_init != NULL)
324 (*native_cpu_freq_init)(cpu_vendor);
325
326 return rv;
327 }
328
329 int
330 acpicpu_md_pstate_stop(void)
331 {
332
333 if (cpu_freq_sysctllog != NULL) {
334 sysctl_teardown(&cpu_freq_sysctllog);
335 cpu_freq_sysctllog = NULL;
336 }
337
338 if (native_cpu_freq_init != NULL)
339 (*native_cpu_freq_init)(cpu_vendor);
340
341 return 0;
342 }
343
344 static int
345 acpicpu_md_pstate_sysctl_get(SYSCTLFN_ARGS)
346 {
347 struct cpu_info *ci = curcpu();
348 struct acpicpu_softc *sc;
349 struct sysctlnode node;
350 uint32_t freq;
351 int err;
352
353 sc = acpicpu_sc[ci->ci_acpiid];
354
355 if (sc == NULL)
356 return ENXIO;
357
358 err = acpicpu_pstate_get(sc, &freq);
359
360 if (err != 0)
361 return err;
362
363 node = *rnode;
364 node.sysctl_data = &freq;
365
366 err = sysctl_lookup(SYSCTLFN_CALL(&node));
367
368 if (err != 0 || newp == NULL)
369 return err;
370
371 return 0;
372 }
373
374 static int
375 acpicpu_md_pstate_sysctl_set(SYSCTLFN_ARGS)
376 {
377 struct cpu_info *ci = curcpu();
378 struct acpicpu_softc *sc;
379 struct sysctlnode node;
380 uint32_t freq;
381 int err;
382
383 sc = acpicpu_sc[ci->ci_acpiid];
384
385 if (sc == NULL)
386 return ENXIO;
387
388 err = acpicpu_pstate_get(sc, &freq);
389
390 if (err != 0)
391 return err;
392
393 node = *rnode;
394 node.sysctl_data = &freq;
395
396 err = sysctl_lookup(SYSCTLFN_CALL(&node));
397
398 if (err != 0 || newp == NULL)
399 return err;
400
401 err = acpicpu_pstate_set(sc, freq);
402
403 if (err != 0)
404 return err;
405
406 return 0;
407 }
408
409 static int
410 acpicpu_md_pstate_sysctl_all(SYSCTLFN_ARGS)
411 {
412 struct cpu_info *ci = curcpu();
413 struct acpicpu_softc *sc;
414 struct sysctlnode node;
415 char buf[1024];
416 size_t len;
417 uint32_t i;
418 int err;
419
420 sc = acpicpu_sc[ci->ci_acpiid];
421
422 if (sc == NULL)
423 return ENXIO;
424
425 (void)memset(&buf, 0, sizeof(buf));
426
427 mutex_enter(&sc->sc_mtx);
428
429 for (len = 0, i = sc->sc_pstate_max; i < sc->sc_pstate_count; i++) {
430
431 if (sc->sc_pstate[i].ps_freq == 0)
432 continue;
433
434 len += snprintf(buf + len, sizeof(buf) - len, "%u%s",
435 sc->sc_pstate[i].ps_freq,
436 i < (sc->sc_pstate_count - 1) ? " " : "");
437 }
438
439 mutex_exit(&sc->sc_mtx);
440
441 node = *rnode;
442 node.sysctl_data = buf;
443
444 err = sysctl_lookup(SYSCTLFN_CALL(&node));
445
446 if (err != 0 || newp == NULL)
447 return err;
448
449 return 0;
450 }
451
452 int
453 acpicpu_md_pstate_get(struct acpicpu_softc *sc, uint32_t *freq)
454 {
455 struct acpicpu_pstate *ps = NULL;
456 uint64_t val;
457 uint32_t i;
458
459 for (i = 0; i < sc->sc_pstate_count; i++) {
460
461 ps = &sc->sc_pstate[i];
462
463 if (ps->ps_freq != 0)
464 break;
465 }
466
467 if (__predict_false(ps == NULL))
468 return EINVAL;
469
470 switch (cpu_vendor) {
471
472 case CPUVENDOR_INTEL:
473 ps->ps_status_addr = MSR_PERF_STATUS;
474 ps->ps_status_mask = __BITS(0, 15);
475 break;
476
477 case CPUVENDOR_AMD:
478
479 if ((ps->ps_flags & ACPICPU_FLAG_P_XPSS) == 0)
480 return EOPNOTSUPP;
481
482 break;
483
484 default:
485 return ENODEV;
486 }
487
488 if (ps->ps_status_addr == 0)
489 return EINVAL;
490
491 val = rdmsr(ps->ps_status_addr);
492
493 if (ps->ps_status_mask != 0)
494 val = val & ps->ps_status_mask;
495
496 for (i = 0; i < sc->sc_pstate_count; i++) {
497
498 ps = &sc->sc_pstate[i];
499
500 if (ps->ps_freq == 0)
501 continue;
502
503 if (val == ps->ps_status) {
504 *freq = ps->ps_freq;
505 return 0;
506 }
507 }
508
509 return EIO;
510 }
511
512 int
513 acpicpu_md_pstate_set(struct acpicpu_pstate *ps)
514 {
515 struct msr_rw_info msr;
516 uint64_t xc, val;
517 int i;
518
519 switch (cpu_vendor) {
520
521 case CPUVENDOR_INTEL:
522 ps->ps_control_addr = MSR_PERF_CTL;
523 ps->ps_control_mask = __BITS(0, 15);
524
525 ps->ps_status_addr = MSR_PERF_STATUS;
526 ps->ps_status_mask = __BITS(0, 15);
527 break;
528
529 case CPUVENDOR_AMD:
530
531 if ((ps->ps_flags & ACPICPU_FLAG_P_XPSS) == 0)
532 return EOPNOTSUPP;
533
534 break;
535
536 default:
537 return ENODEV;
538 }
539
540 msr.msr_read = false;
541 msr.msr_type = ps->ps_control_addr;
542 msr.msr_value = ps->ps_control;
543
544 if (ps->ps_control_mask != 0) {
545 msr.msr_mask = ps->ps_control_mask;
546 msr.msr_read = true;
547 }
548
549 xc = xc_broadcast(0, (xcfunc_t)x86_msr_xcall, &msr, NULL);
550 xc_wait(xc);
551
552 if (ps->ps_status_addr == 0)
553 return 0;
554
555 for (i = val = 0; i < ACPICPU_P_STATE_RETRY; i++) {
556
557 val = rdmsr(ps->ps_status_addr);
558
559 if (ps->ps_status_mask != 0)
560 val = val & ps->ps_status_mask;
561
562 if (val == ps->ps_status)
563 return 0;
564
565 DELAY(ps->ps_latency);
566 }
567
568 return EAGAIN;
569 }
570
571 int
572 acpicpu_md_tstate_get(struct acpicpu_softc *sc, uint32_t *percent)
573 {
574 struct acpicpu_tstate *ts;
575 uint64_t val, sta;
576 uint32_t i;
577
578 switch (cpu_vendor) {
579
580 case CPUVENDOR_INTEL:
581 sta = MSR_THERM_CONTROL;
582 break;
583
584 default:
585 return ENODEV;
586 }
587
588 val = rdmsr(sta);
589
590 for (i = 0; i < sc->sc_tstate_count; i++) {
591
592 ts = &sc->sc_tstate[i];
593
594 if (ts->ts_percent == 0)
595 continue;
596
597 if (val == ts->ts_control || val == ts->ts_status) {
598 *percent = ts->ts_percent;
599 return 0;
600 }
601 }
602
603 return EIO;
604 }
605
606 int
607 acpicpu_md_tstate_set(struct acpicpu_tstate *ts)
608 {
609 struct msr_rw_info msr;
610 uint64_t xc, val, sta;
611 uint32_t i;
612
613 switch (cpu_vendor) {
614
615 case CPUVENDOR_INTEL:
616 msr.msr_read = true;
617 msr.msr_type = MSR_THERM_CONTROL;
618 msr.msr_value = ts->ts_control;
619 msr.msr_mask = __BITS(1, 4);
620
621 sta = MSR_THERM_CONTROL;
622 break;
623
624 default:
625 return ENODEV;
626 }
627
628 xc = xc_broadcast(0, (xcfunc_t)x86_msr_xcall, &msr, NULL);
629 xc_wait(xc);
630
631 if (ts->ts_status == 0)
632 return 0;
633
634 for (i = val = 0; i < ACPICPU_T_STATE_RETRY; i++) {
635
636 val = rdmsr(sta);
637
638 if (val == ts->ts_status)
639 return 0;
640
641 DELAY(ts->ts_latency);
642 }
643
644 return EAGAIN;
645 }
646