acpi_cpu.c revision 1.4 1 /* $NetBSD: acpi_cpu.c,v 1.4 2010/07/21 14:59:31 cegger 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.c,v 1.4 2010/07/21 14:59:31 cegger Exp $");
31
32 #include <sys/param.h>
33 #include <sys/cpu.h>
34 #include <sys/kernel.h>
35 #include <sys/kmem.h>
36 #include <sys/module.h>
37 #include <sys/once.h>
38
39 #include <dev/acpi/acpireg.h>
40 #include <dev/acpi/acpivar.h>
41 #include <dev/acpi/acpi_cpu.h>
42
43 #include <machine/acpi_machdep.h>
44
45 #define _COMPONENT ACPI_BUS_COMPONENT
46 ACPI_MODULE_NAME ("acpi_cpu")
47
48 static int acpicpu_match(device_t, cfdata_t, void *);
49 static void acpicpu_attach(device_t, device_t, void *);
50 static int acpicpu_detach(device_t, int);
51 static int acpicpu_once_attach(void);
52 static int acpicpu_once_detach(void);
53
54 static int acpicpu_object(ACPI_HANDLE, struct acpicpu_object *);
55 static cpuid_t acpicpu_id(uint32_t);
56 static uint32_t acpicpu_cap(struct acpicpu_softc *);
57 static ACPI_OBJECT *acpicpu_cap_init(void);
58 static ACPI_STATUS acpicpu_cap_pdc(ACPI_HANDLE);
59 static ACPI_STATUS acpicpu_cap_osc(ACPI_HANDLE, uint32_t *);
60 static const char *acpicpu_cap_oscerr(uint32_t);
61 static void acpicpu_notify(ACPI_HANDLE, uint32_t, void *);
62 static bool acpicpu_suspend(device_t, const pmf_qual_t *);
63 static bool acpicpu_resume(device_t, const pmf_qual_t *);
64
65 kmutex_t acpicpu_mtx;
66 struct acpicpu_softc **acpicpu_sc = NULL;
67
68 static const char * const acpicpu_hid[] = {
69 "ACPI0007",
70 NULL
71 };
72
73 CFATTACH_DECL_NEW(acpicpu, sizeof(struct acpicpu_softc),
74 acpicpu_match, acpicpu_attach, acpicpu_detach, NULL);
75
76 static int
77 acpicpu_match(device_t parent, cfdata_t match, void *aux)
78 {
79 struct acpi_attach_args *aa = aux;
80 struct acpicpu_object ao;
81
82 if (aa->aa_node->ad_type != ACPI_TYPE_PROCESSOR)
83 return 0;
84
85 if (acpi_match_hid(aa->aa_node->ad_devinfo, acpicpu_hid) != 0)
86 return 1;
87
88 int rv = acpicpu_object(aa->aa_node->ad_handle, &ao);
89 if (rv == 0 || acpicpu_id(ao.ao_procid) == 0xFFFFFF)
90 return 0;
91 return 1;
92 }
93
94 static void
95 acpicpu_attach(device_t parent, device_t self, void *aux)
96 {
97 struct acpicpu_softc *sc = device_private(self);
98 struct acpi_attach_args *aa = aux;
99 static ONCE_DECL(once_attach);
100 int rv;
101
102 rv = acpicpu_object(aa->aa_node->ad_handle, &sc->sc_object);
103
104 if (rv == 0)
105 return;
106
107 rv = RUN_ONCE(&once_attach, acpicpu_once_attach);
108
109 if (rv != 0)
110 return;
111
112 KASSERT(acpicpu_sc != NULL);
113
114 mutex_enter(&acpicpu_mtx);
115
116 sc->sc_dev = self;
117 sc->sc_iot = aa->aa_iot;
118 sc->sc_node = aa->aa_node;
119 sc->sc_cpuid = acpicpu_id(sc->sc_object.ao_procid);
120
121 if (sc->sc_cpuid == 0xFFFFFF) {
122 mutex_exit(&acpicpu_mtx);
123 aprint_error(": invalid CPU ID\n");
124 return;
125 }
126
127 if (acpicpu_sc[sc->sc_cpuid] != NULL) {
128 mutex_exit(&acpicpu_mtx);
129 aprint_error(": already probed\n");
130 return;
131 }
132
133 acpicpu_sc[sc->sc_cpuid] = sc;
134 mutex_exit(&acpicpu_mtx);
135
136 sc->sc_cap = acpicpu_cap(sc);
137 sc->sc_flags |= acpicpu_md_quirks();
138
139 aprint_naive("\n");
140 aprint_normal(": ACPI CPU");
141 aprint_verbose(", cap 0x%02x, addr 0x%06x, len 0x%02x",
142 sc->sc_cap, sc->sc_object.ao_pblkaddr, sc->sc_object.ao_pblklen);
143 aprint_normal("\n");
144
145 /*
146 * We should claim the bus space. However, we do this only
147 * to announce that the space is in use. This is unnecessary
148 * if system I/O type C-states are not used. Many systems also
149 * report invalid values in the processor object. Finally, this
150 * is known to conflict with other devices. But as is noted in
151 * ichlpcib(4), we can continue our I/O without bus_space(9).
152 */
153 if (sc->sc_object.ao_pblklen == 6 && sc->sc_object.ao_pblkaddr != 0) {
154
155 rv = bus_space_map(sc->sc_iot, sc->sc_object.ao_pblkaddr,
156 sc->sc_object.ao_pblklen, 0, &sc->sc_ioh);
157
158 if (rv != 0)
159 sc->sc_ioh = 0;
160 }
161
162 acpicpu_cstate_attach(self);
163
164 (void)acpi_register_notify(sc->sc_node, acpicpu_notify);
165 (void)config_finalize_register(self, acpicpu_cstate_start);
166 (void)pmf_device_register(self, acpicpu_suspend, acpicpu_resume);
167 }
168
169 static int
170 acpicpu_detach(device_t self, int flags)
171 {
172 struct acpicpu_softc *sc = device_private(self);
173 const bus_addr_t addr = sc->sc_object.ao_pblkaddr;
174 static ONCE_DECL(once_detach);
175 int rv = 0;
176
177 acpi_deregister_notify(sc->sc_node);
178
179 if ((sc->sc_flags & ACPICPU_FLAG_C) != 0)
180 rv = acpicpu_cstate_detach(self);
181
182 if (rv != 0)
183 return rv;
184
185 rv = RUN_ONCE(&once_detach, acpicpu_once_detach);
186
187 if (rv != 0)
188 return rv;
189
190 if (sc->sc_ioh != 0)
191 bus_space_unmap(sc->sc_iot, sc->sc_ioh, addr);
192
193 return 0;
194 }
195
196 static int
197 acpicpu_once_attach(void)
198 {
199 struct acpicpu_softc *sc;
200 unsigned int i;
201
202 acpicpu_sc = kmem_zalloc(maxcpus * sizeof(*sc), KM_SLEEP);
203
204 if (acpicpu_sc == NULL)
205 return ENOMEM;
206
207 for (i = 0; i < maxcpus; i++)
208 acpicpu_sc[i] = NULL;
209
210 mutex_init(&acpicpu_mtx, MUTEX_DEFAULT, IPL_VM);
211
212 return 0;
213 }
214
215 static int
216 acpicpu_once_detach(void)
217 {
218 struct acpicpu_softc *sc;
219
220 KASSERT(acpicpu_sc != NULL);
221
222 mutex_destroy(&acpicpu_mtx);
223 kmem_free(acpicpu_sc, maxcpus * sizeof(*sc));
224 acpicpu_sc = NULL;
225
226 return 0;
227 }
228
229 static int
230 acpicpu_object(ACPI_HANDLE hdl, struct acpicpu_object *ao)
231 {
232 ACPI_OBJECT *obj;
233 ACPI_BUFFER buf;
234 ACPI_STATUS rv;
235
236 rv = acpi_eval_struct(hdl, NULL, &buf);
237
238 if (ACPI_FAILURE(rv))
239 return 0;
240
241 obj = buf.Pointer;
242
243 if (obj->Type != ACPI_TYPE_PROCESSOR) {
244 rv = AE_TYPE;
245 goto out;
246 }
247
248 if (obj->Processor.ProcId > (uint32_t)maxcpus) {
249 rv = AE_LIMIT;
250 goto out;
251 }
252
253 KDASSERT((uint64_t)obj->Processor.PblkAddress < UINT32_MAX);
254
255 if (ao != NULL) {
256 ao->ao_procid = obj->Processor.ProcId;
257 ao->ao_pblklen = obj->Processor.PblkLength;
258 ao->ao_pblkaddr = obj->Processor.PblkAddress;
259 }
260
261 out:
262 if (buf.Pointer != NULL)
263 ACPI_FREE(buf.Pointer);
264
265 return ACPI_FAILURE(rv) ? 0 : 1;
266 }
267
268 static cpuid_t
269 acpicpu_id(uint32_t id)
270 {
271 CPU_INFO_ITERATOR cii;
272 struct cpu_info *ci;
273
274 for (CPU_INFO_FOREACH(cii, ci)) {
275 if (id == ci->ci_cpuid)
276 return id;
277 }
278
279 return 0xFFFFFF;
280 }
281
282 static uint32_t
283 acpicpu_cap(struct acpicpu_softc *sc)
284 {
285 uint32_t cap[3] = { 0 };
286 ACPI_STATUS rv;
287 int err;
288
289 /*
290 * Set machine-dependent processor capabilities.
291 *
292 * The _PDC was deprecated in ACPI 3.0 in favor of the _OSC,
293 * but firmware may expect that we evaluate it nevertheless.
294 */
295 rv = acpicpu_cap_pdc(sc->sc_node->ad_handle);
296
297 if (ACPI_FAILURE(rv) && rv != AE_NOT_FOUND)
298 aprint_error_dev(sc->sc_dev, "failed to evaluate _PDC: "
299 "%s\n", AcpiFormatException(rv));
300
301 rv = acpicpu_cap_osc(sc->sc_node->ad_handle, cap);
302
303 if (ACPI_FAILURE(rv) && rv != AE_NOT_FOUND)
304 aprint_error_dev(sc->sc_dev, "failed to evaluate _OSC: "
305 "%s\n", AcpiFormatException(rv));
306
307 if (ACPI_SUCCESS(rv)) {
308
309 err = cap[0] & ~__BIT(0);
310
311 if (err != 0) {
312 aprint_error_dev(sc->sc_dev, "errors in "
313 "_OSC: %s\n", acpicpu_cap_oscerr(err));
314 cap[2] = 0;
315 }
316 }
317
318 return cap[2];
319 }
320
321 static ACPI_OBJECT *
322 acpicpu_cap_init(void)
323 {
324 static uint32_t cap[3];
325 static ACPI_OBJECT obj;
326
327 cap[0] = ACPICPU_PDC_REVID;
328 cap[1] = 1;
329 cap[2] = acpicpu_md_cap();
330
331 obj.Type = ACPI_TYPE_BUFFER;
332 obj.Buffer.Length = sizeof(cap);
333 obj.Buffer.Pointer = (uint8_t *)cap;
334
335 return &obj;
336 }
337
338 static ACPI_STATUS
339 acpicpu_cap_pdc(ACPI_HANDLE hdl)
340 {
341 ACPI_OBJECT_LIST arg_list;
342
343 arg_list.Count = 1;
344 arg_list.Pointer = acpicpu_cap_init();
345
346 return AcpiEvaluateObject(hdl, "_PDC", &arg_list, NULL);
347 }
348
349 static ACPI_STATUS
350 acpicpu_cap_osc(ACPI_HANDLE hdl, uint32_t *val)
351 {
352 ACPI_OBJECT_LIST arg_list;
353 ACPI_OBJECT *cap, *obj;
354 ACPI_OBJECT arg[4];
355 ACPI_BUFFER buf;
356 ACPI_STATUS rv;
357
358 /* Intel. */
359 static uint8_t cpu_oscuuid[16] = {
360 0x16, 0xA6, 0x77, 0x40, 0x0C, 0x29, 0xBE, 0x47,
361 0x9E, 0xBD, 0xD8, 0x70, 0x58, 0x71, 0x39, 0x53
362 };
363
364 cap = acpicpu_cap_init();
365
366 arg_list.Count = 4;
367 arg_list.Pointer = arg;
368
369 arg[0].Type = ACPI_TYPE_BUFFER;
370 arg[0].Buffer.Length = sizeof(cpu_oscuuid);
371 arg[0].Buffer.Pointer = cpu_oscuuid;
372
373 arg[1].Type = ACPI_TYPE_INTEGER;
374 arg[1].Integer.Value = ACPICPU_PDC_REVID;
375
376 arg[2].Type = ACPI_TYPE_INTEGER;
377 arg[2].Integer.Value = cap->Buffer.Length / sizeof(uint32_t);
378
379 arg[3] = *cap;
380
381 buf.Pointer = NULL;
382 buf.Length = ACPI_ALLOCATE_LOCAL_BUFFER;
383
384 rv = AcpiEvaluateObject(hdl, "_OSC", &arg_list, &buf);
385
386 if (ACPI_FAILURE(rv))
387 return rv;
388
389 obj = buf.Pointer;
390
391 if (obj->Type != ACPI_TYPE_BUFFER) {
392 rv = AE_TYPE;
393 goto out;
394 }
395
396 if (obj->Buffer.Length != cap->Buffer.Length) {
397 rv = AE_BUFFER_OVERFLOW;
398 goto out;
399 }
400
401 (void)memcpy(val, obj->Buffer.Pointer, obj->Buffer.Length);
402
403 out:
404 if (buf.Pointer != NULL)
405 ACPI_FREE(buf.Pointer);
406
407 return rv;
408 }
409
410 static const char *
411 acpicpu_cap_oscerr(uint32_t err)
412 {
413
414 KASSERT((err & __BIT(0)) == 0);
415
416 if ((err & __BIT(1)) != 0)
417 return "_OSC failure";
418
419 if ((err & __BIT(2)) != 0)
420 return "unrecognized UUID";
421
422 if ((err & __BIT(3)) != 0)
423 return "unrecognized revision";
424
425 if ((err & __BIT(4)) != 0)
426 return "capabilities masked";
427
428 return "unknown error";
429 }
430
431 static void
432 acpicpu_notify(ACPI_HANDLE hdl, uint32_t evt, void *aux)
433 {
434 ACPI_OSD_EXEC_CALLBACK func;
435 struct acpicpu_softc *sc;
436 device_t self = aux;
437
438 sc = device_private(self);
439
440 if ((sc->sc_flags & ACPICPU_FLAG_INIT) == 0)
441 return;
442
443 switch (evt) {
444
445 case ACPICPU_C_NOTIFY:
446
447 if ((sc->sc_flags & ACPICPU_FLAG_C) == 0)
448 return;
449
450 func = acpicpu_cstate_callback;
451 break;
452
453 case ACPICPU_P_NOTIFY:
454
455 if ((sc->sc_flags & ACPICPU_FLAG_P) == 0)
456 return;
457
458 func = NULL;
459 break;
460
461 case ACPICPU_T_NOTIFY:
462
463 if ((sc->sc_flags & ACPICPU_FLAG_T) == 0)
464 return;
465
466 func = NULL;
467 break;
468
469 default:
470 aprint_error_dev(sc->sc_dev, "unknown notify: 0x%02X\n", evt);
471 return;
472 }
473
474 (void)AcpiOsExecute(OSL_NOTIFY_HANDLER, func, sc->sc_dev);
475 }
476
477 static bool
478 acpicpu_suspend(device_t self, const pmf_qual_t *qual)
479 {
480 struct acpicpu_softc *sc = device_private(self);
481
482 if ((sc->sc_flags & ACPICPU_FLAG_C) != 0)
483 (void)acpicpu_cstate_suspend(self);
484
485 return true;
486 }
487
488 static bool
489 acpicpu_resume(device_t self, const pmf_qual_t *qual)
490 {
491 struct acpicpu_softc *sc = device_private(self);
492
493 if ((sc->sc_flags & ACPICPU_FLAG_C) != 0)
494 (void)acpicpu_cstate_resume(self);
495
496 return true;
497 }
498
499 #ifdef _MODULE
500
501 MODULE(MODULE_CLASS_DRIVER, acpicpu, NULL);
502 CFDRIVER_DECL(acpicpu, DV_DULL, NULL);
503
504 static int acpicpuloc[] = { -1 };
505 extern struct cfattach acpicpu_ca;
506
507 static struct cfparent acpiparent = {
508 "acpinodebus", NULL, DVUNIT_ANY
509 };
510
511 static struct cfdata acpicpu_cfdata[] = {
512 {
513 .cf_name = "acpicpu",
514 .cf_atname = "acpicpu",
515 .cf_unit = 0,
516 .cf_fstate = FSTATE_STAR,
517 .cf_loc = acpicpuloc,
518 .cf_flags = 0,
519 .cf_pspec = &acpiparent,
520 },
521
522 { NULL, NULL, 0, 0, NULL, 0, NULL }
523 };
524
525 static int
526 acpicpu_modcmd(modcmd_t cmd, void *context)
527 {
528 int err;
529
530 switch (cmd) {
531
532 case MODULE_CMD_INIT:
533
534 err = config_cfdriver_attach(&acpicpu_cd);
535
536 if (err != 0)
537 return err;
538
539 err = config_cfattach_attach("acpicpu", &acpicpu_ca);
540
541 if (err != 0) {
542 config_cfdriver_detach(&acpicpu_cd);
543 return err;
544 }
545
546 err = config_cfdata_attach(acpicpu_cfdata, 1);
547
548 if (err != 0) {
549 config_cfattach_detach("acpicpu", &acpicpu_ca);
550 config_cfdriver_detach(&acpicpu_cd);
551 return err;
552 }
553
554 return 0;
555
556 case MODULE_CMD_FINI:
557
558 err = config_cfdata_detach(acpicpu_cfdata);
559
560 if (err != 0)
561 return err;
562
563 config_cfattach_detach("acpicpu", &acpicpu_ca);
564 config_cfdriver_detach(&acpicpu_cd);
565
566 return 0;
567
568 default:
569 return ENOTTY;
570 }
571 }
572
573 #endif /* _MODULE */
574