acpi/pstate: Allow users to set _PDL
[dragonfly.git] / sys / dev / acpica / acpi_cpu_pstate.c
CommitLineData
c3a2c0df
SZ
1/*
2 * Copyright (c) 2009 The DragonFly Project. All rights reserved.
3 *
4 * This code is derived from software contributed to The DragonFly Project
5 * by Sepherosa Ziehau <sepherosa@gmail.com>
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
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * 3. Neither the name of The DragonFly Project nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific, prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35#include "opt_acpi.h"
36
37#include <sys/param.h>
38#include <sys/bus.h>
39#include <sys/kernel.h>
40#include <sys/malloc.h>
41#include <sys/queue.h>
0e276230 42#include <sys/rman.h>
c3a2c0df 43#include <sys/sysctl.h>
7b46b972 44#include <sys/msgport2.h>
6ac1e346 45#include <sys/cpu_topology.h>
7b46b972 46
5337421c 47#include <net/netisr2.h>
7b46b972
SZ
48#include <net/netmsg2.h>
49#include <net/if_var.h>
c3a2c0df
SZ
50
51#include "acpi.h"
52#include "acpivar.h"
53#include "acpi_cpu.h"
7b46b972 54#include "acpi_cpu_pstate.h"
c3a2c0df
SZ
55
56#define ACPI_NPSTATE_MAX 16
57
58#define ACPI_PSS_PX_NENTRY 6
59
60#define ACPI_PSD_COORD_SWALL 0xfc
61#define ACPI_PSD_COORD_SWANY 0xfd
62#define ACPI_PSD_COORD_HWALL 0xfe
63#define ACPI_PSD_COORD_VALID(coord) \
64 ((coord) == ACPI_PSD_COORD_SWALL || \
65 (coord) == ACPI_PSD_COORD_SWANY || \
66 (coord) == ACPI_PSD_COORD_HWALL)
67
68struct acpi_pst_softc;
69LIST_HEAD(acpi_pst_list, acpi_pst_softc);
70
7b46b972 71struct netmsg_acpi_pst {
002c1265 72 struct netmsg_base base;
76418417
SZ
73 const struct acpi_pst_res *ctrl;
74 const struct acpi_pst_res *status;
7b46b972
SZ
75};
76
c3a2c0df
SZ
77struct acpi_pst_domain {
78 uint32_t pd_dom;
79 uint32_t pd_coord;
80 uint32_t pd_nproc;
81 LIST_ENTRY(acpi_pst_domain) pd_link;
82
83 uint32_t pd_flags;
84
85 int pd_state;
c3a2c0df
SZ
86 struct acpi_pst_list pd_pstlist;
87
88 struct sysctl_ctx_list pd_sysctl_ctx;
89 struct sysctl_oid *pd_sysctl_tree;
90};
91LIST_HEAD(acpi_pst_domlist, acpi_pst_domain);
92
93#define ACPI_PSTDOM_FLAG_STUB 0x1 /* stub domain, no _PSD */
7b46b972 94#define ACPI_PSTDOM_FLAG_DEAD 0x2 /* domain can't be started */
0cb292d1 95#define ACPI_PSTDOM_FLAG_INT 0x4 /* domain created from Integer _PSD */
c3a2c0df
SZ
96
97struct acpi_pst_softc {
7b46b972 98 device_t pst_dev;
41d9045e 99 struct acpi_cpu_softc *pst_parent;
c3a2c0df 100 struct acpi_pst_domain *pst_domain;
76418417
SZ
101 struct acpi_pst_res pst_creg;
102 struct acpi_pst_res pst_sreg;
c3a2c0df
SZ
103
104 int pst_state;
c3a2c0df
SZ
105 int pst_cpuid;
106
107 ACPI_HANDLE pst_handle;
108
109 LIST_ENTRY(acpi_pst_softc) pst_link;
110};
111
c3a2c0df
SZ
112static int acpi_pst_probe(device_t dev);
113static int acpi_pst_attach(device_t dev);
114
115static void acpi_pst_postattach(void *);
116static struct acpi_pst_domain *
0cb292d1
SZ
117 acpi_pst_domain_create_int(device_t, uint32_t);
118static struct acpi_pst_domain *
119 acpi_pst_domain_create_pkg(device_t, ACPI_OBJECT *);
c3a2c0df
SZ
120static struct acpi_pst_domain *
121 acpi_pst_domain_find(uint32_t);
122static struct acpi_pst_domain *
123 acpi_pst_domain_alloc(uint32_t, uint32_t, uint32_t);
7b46b972 124static int acpi_pst_domain_set_pstate(struct acpi_pst_domain *, int);
6ac1e346 125static void acpi_pst_domain_check_nproc(device_t, struct acpi_pst_domain *);
446b8384 126static int acpi_pst_global_set_pstate(int);
7b46b972
SZ
127
128static int acpi_pst_check_csr(struct acpi_pst_softc *);
129static int acpi_pst_check_pstates(struct acpi_pst_softc *);
c5479e60 130static int acpi_pst_init(struct acpi_pst_softc *);
7b46b972
SZ
131static int acpi_pst_set_pstate(struct acpi_pst_softc *,
132 const struct acpi_pstate *);
133static const struct acpi_pstate *
134 acpi_pst_get_pstate(struct acpi_pst_softc *);
0e276230
SZ
135static int acpi_pst_alloc_resource(device_t, ACPI_OBJECT *, int,
136 struct acpi_pst_res *);
7b46b972 137
002c1265
MD
138static void acpi_pst_check_csr_handler(netmsg_t);
139static void acpi_pst_check_pstates_handler(netmsg_t);
140static void acpi_pst_init_handler(netmsg_t);
141static void acpi_pst_set_pstate_handler(netmsg_t);
142static void acpi_pst_get_pstate_handler(netmsg_t);
c3a2c0df
SZ
143
144static int acpi_pst_sysctl_freqs(SYSCTL_HANDLER_ARGS);
1555fc97 145static int acpi_pst_sysctl_freqs_bin(SYSCTL_HANDLER_ARGS);
c3a2c0df 146static int acpi_pst_sysctl_members(SYSCTL_HANDLER_ARGS);
7b46b972
SZ
147static int acpi_pst_sysctl_select(SYSCTL_HANDLER_ARGS);
148static int acpi_pst_sysctl_global(SYSCTL_HANDLER_ARGS);
c3a2c0df
SZ
149
150static struct acpi_pst_domlist acpi_pst_domains =
151 LIST_HEAD_INITIALIZER(acpi_pst_domains);
381b8691 152static int acpi_pst_domain_id;
c3a2c0df 153
7b46b972
SZ
154static int acpi_pst_global_state;
155
15e3104c 156static int acpi_pstate_start = -1;
c8676324 157static int acpi_pstate_count;
c3a2c0df
SZ
158static int acpi_npstates;
159static struct acpi_pstate *acpi_pstates;
160
7b46b972
SZ
161static const struct acpi_pst_md *acpi_pst_md;
162
8ca16411
SZ
163static int acpi_pst_pdl = -1;
164TUNABLE_INT("hw.acpi.cpu.pst.pdl", &acpi_pst_pdl);
165
6ac1e346
SZ
166static int acpi_pst_ht_reuse_domain = 1;
167TUNABLE_INT("hw.acpi.cpu.pst.ht_reuse_domain", &acpi_pst_ht_reuse_domain);
168
dbe50d54
SZ
169static int acpi_pst_force_pkg_domain = 0;
170TUNABLE_INT("hw.acpi.cpu.pst.force_pkg_domain", &acpi_pst_force_pkg_domain);
171
c3a2c0df
SZ
172static device_method_t acpi_pst_methods[] = {
173 /* Device interface */
174 DEVMETHOD(device_probe, acpi_pst_probe),
175 DEVMETHOD(device_attach, acpi_pst_attach),
176 DEVMETHOD(device_detach, bus_generic_detach),
177 DEVMETHOD(device_shutdown, bus_generic_shutdown),
178 DEVMETHOD(device_suspend, bus_generic_suspend),
179 DEVMETHOD(device_resume, bus_generic_resume),
180
181 /* Bus interface */
182 DEVMETHOD(bus_add_child, bus_generic_add_child),
183 DEVMETHOD(bus_print_child, bus_generic_print_child),
184 DEVMETHOD(bus_read_ivar, bus_generic_read_ivar),
185 DEVMETHOD(bus_write_ivar, bus_generic_write_ivar),
186 DEVMETHOD(bus_get_resource_list, bus_generic_get_resource_list),
187 DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource),
188 DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource),
189 DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource),
190 DEVMETHOD(bus_release_resource, bus_generic_release_resource),
191 DEVMETHOD(bus_driver_added, bus_generic_driver_added),
192 DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
193 DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
194 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
195 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
196
d3c9c58e 197 DEVMETHOD_END
c3a2c0df
SZ
198};
199
200static driver_t acpi_pst_driver = {
201 "cpu_pst",
202 acpi_pst_methods,
203 sizeof(struct acpi_pst_softc)
204};
205
206static devclass_t acpi_pst_devclass;
aa2b9d05 207DRIVER_MODULE(cpu_pst, cpu, acpi_pst_driver, acpi_pst_devclass, NULL, NULL);
c3a2c0df
SZ
208MODULE_DEPEND(cpu_pst, acpi, 1, 1, 1);
209
7b46b972
SZ
210static __inline int
211acpi_pst_freq2index(int freq)
212{
213 int i;
214
215 for (i = 0; i < acpi_npstates; ++i) {
216 if (acpi_pstates[i].st_freq == freq)
217 return i;
218 }
219 return -1;
220}
221
c3a2c0df
SZ
222static int
223acpi_pst_probe(device_t dev)
224{
225 ACPI_BUFFER buf;
226 ACPI_HANDLE handle;
227 ACPI_STATUS status;
228 ACPI_OBJECT *obj;
229
230 if (acpi_disabled("cpu_pst") ||
231 acpi_get_type(dev) != ACPI_TYPE_PROCESSOR)
232 return ENXIO;
233
7b46b972
SZ
234 if (acpi_pst_md == NULL)
235 acpi_pst_md = acpi_pst_md_probe();
236
c3a2c0df
SZ
237 handle = acpi_get_handle(dev);
238
6ac1e346
SZ
239 /*
240 * Check _PSD package
241 *
242 * NOTE:
243 * Some BIOSes do not expose _PCT for the second thread of
244 * CPU cores. In this case, _PSD should be enough to get the
245 * P-state of the second thread working, since it must have
246 * the same _PCT and _PSS as the first thread in the same
247 * core.
248 */
249 buf.Pointer = NULL;
250 buf.Length = ACPI_ALLOCATE_BUFFER;
251 status = AcpiEvaluateObject(handle, "_PSD", NULL, &buf);
252 if (!ACPI_FAILURE(status)) {
253 AcpiOsFree((ACPI_OBJECT *)buf.Pointer);
254 goto done;
255 }
256
c3a2c0df
SZ
257 /*
258 * Check _PCT package
259 */
260 buf.Pointer = NULL;
261 buf.Length = ACPI_ALLOCATE_BUFFER;
262 status = AcpiEvaluateObject(handle, "_PCT", NULL, &buf);
263 if (ACPI_FAILURE(status)) {
604bd1e4
SZ
264 if (bootverbose) {
265 device_printf(dev, "Can't get _PCT package - %s\n",
266 AcpiFormatException(status));
267 }
c3a2c0df
SZ
268 return ENXIO;
269 }
270
271 obj = (ACPI_OBJECT *)buf.Pointer;
272 if (!ACPI_PKG_VALID_EQ(obj, 2)) {
273 device_printf(dev, "Invalid _PCT package\n");
274 AcpiOsFree(obj);
275 return ENXIO;
276 }
277 AcpiOsFree(obj);
278
279 /*
280 * Check _PSS package
281 */
282 buf.Pointer = NULL;
283 buf.Length = ACPI_ALLOCATE_BUFFER;
284 status = AcpiEvaluateObject(handle, "_PSS", NULL, &buf);
285 if (ACPI_FAILURE(status)) {
286 device_printf(dev, "Can't get _PSS package - %s\n",
287 AcpiFormatException(status));
288 return ENXIO;
289 }
290
291 obj = (ACPI_OBJECT *)buf.Pointer;
292 if (!ACPI_PKG_VALID(obj, 1)) {
293 device_printf(dev, "Invalid _PSS package\n");
294 AcpiOsFree(obj);
295 return ENXIO;
296 }
297 AcpiOsFree(obj);
298
6ac1e346 299done:
c3a2c0df
SZ
300 device_set_desc(dev, "ACPI CPU P-State");
301 return 0;
302}
303
304static int
305acpi_pst_attach(device_t dev)
306{
dbe50d54 307 struct acpi_pst_softc *sc = device_get_softc(dev);
c3a2c0df
SZ
308 struct acpi_pst_domain *dom = NULL;
309 ACPI_BUFFER buf;
310 ACPI_STATUS status;
76418417 311 ACPI_OBJECT *obj;
c3a2c0df 312 struct acpi_pstate *pstate, *p;
c8676324 313 int i, npstate, error, sstart, scount;
c3a2c0df 314
7b46b972 315 sc->pst_dev = dev;
c3a2c0df
SZ
316 sc->pst_parent = device_get_softc(device_get_parent(dev));
317 sc->pst_handle = acpi_get_handle(dev);
318 sc->pst_cpuid = acpi_get_magic(dev);
319
320 /*
321 * If there is a _PSD, then we create procossor domain
322 * accordingly. If there is no _PSD, we just fake a
323 * default processor domain0.
324 */
325 buf.Pointer = NULL;
326 buf.Length = ACPI_ALLOCATE_BUFFER;
327 status = AcpiEvaluateObject(sc->pst_handle, "_PSD", NULL, &buf);
328 if (!ACPI_FAILURE(status)) {
6ec50a1c
SZ
329 obj = (ACPI_OBJECT *)buf.Pointer;
330
6f36cba1
SZ
331 if (acpi_pst_domain_id > 0) {
332 device_printf(dev, "Missing _PSD for certain CPUs\n");
333 AcpiOsFree(obj);
334 return ENXIO;
335 }
336 acpi_pst_domain_id = -1;
337
c3a2c0df 338 if (ACPI_PKG_VALID_EQ(obj, 1)) {
0cb292d1 339 dom = acpi_pst_domain_create_pkg(dev,
c3a2c0df
SZ
340 &obj->Package.Elements[0]);
341 if (dom == NULL) {
342 AcpiOsFree(obj);
343 return ENXIO;
344 }
345 } else {
0cb292d1
SZ
346 if (obj->Type != ACPI_TYPE_INTEGER) {
347 device_printf(dev,
348 "Invalid _PSD package, Type 0x%x\n",
349 obj->Type);
350 AcpiOsFree(obj);
351 return ENXIO;
352 } else {
353 device_printf(dev, "Integer _PSD %ju\n",
354 (uintmax_t)obj->Integer.Value);
355 dom = acpi_pst_domain_create_int(dev,
356 obj->Integer.Value);
357 if (dom == NULL) {
358 AcpiOsFree(obj);
359 return ENXIO;
360 }
361 }
c3a2c0df
SZ
362 }
363
364 /* Free _PSD */
365 AcpiOsFree(buf.Pointer);
366 } else {
6f36cba1
SZ
367 if (acpi_pst_domain_id < 0) {
368 device_printf(dev, "Missing _PSD for cpu%d\n",
369 sc->pst_cpuid);
370 return ENXIO;
371 }
372
381b8691
SZ
373 /*
374 * Create a stub one processor domain for each processor
375 */
376 dom = acpi_pst_domain_alloc(acpi_pst_domain_id,
377 ACPI_PSD_COORD_SWANY, 1);
c3a2c0df 378 dom->pd_flags |= ACPI_PSTDOM_FLAG_STUB;
381b8691
SZ
379
380 ++acpi_pst_domain_id;
c3a2c0df
SZ
381 }
382
383 /* Make sure that adding us will not overflow our domain */
6ac1e346 384 acpi_pst_domain_check_nproc(dev, dom);
c3a2c0df
SZ
385
386 /*
387 * Get control/status registers from _PCT
388 */
389 buf.Pointer = NULL;
390 buf.Length = ACPI_ALLOCATE_BUFFER;
391 status = AcpiEvaluateObject(sc->pst_handle, "_PCT", NULL, &buf);
392 if (ACPI_FAILURE(status)) {
dbe50d54
SZ
393 struct acpi_pst_softc *pst;
394
6ac1e346
SZ
395 /*
396 * No _PCT. See the comment in acpi_pst_probe() near
397 * _PSD check.
398 *
399 * Use control/status registers of another CPU in the
400 * same domain, or in the same core, if the type of
401 * these registers are "Fixed Hardware", e.g. on most
402 * of the model Intel CPUs.
403 */
404 pst = LIST_FIRST(&dom->pd_pstlist);
405 if (pst == NULL) {
406 cpumask_t mask;
407
408 mask = get_cpumask_from_level(sc->pst_cpuid,
409 CORE_LEVEL);
410 if (CPUMASK_TESTNZERO(mask)) {
411 struct acpi_pst_domain *dom1;
412
413 LIST_FOREACH(dom1, &acpi_pst_domains, pd_link) {
414 LIST_FOREACH(pst, &dom1->pd_pstlist,
415 pst_link) {
416 if (CPUMASK_TESTBIT(mask,
417 pst->pst_cpuid))
418 break;
419 }
420 if (pst != NULL)
421 break;
422 }
423 if (pst != NULL && acpi_pst_ht_reuse_domain) {
424 /*
425 * Use the same domain for CPUs in the
426 * same core.
427 */
428 device_printf(dev, "Destroy domain%u, "
429 "reuse domain%u\n",
430 dom->pd_dom, dom1->pd_dom);
431 LIST_REMOVE(dom, pd_link);
432 kfree(dom, M_DEVBUF);
433 dom = dom1;
434 /*
435 * Make sure that adding us will not
436 * overflow the domain containing
437 * siblings in the same core.
438 */
439 acpi_pst_domain_check_nproc(dev, dom);
440 }
441 }
442 }
443 if (pst != NULL &&
444 pst->pst_creg.pr_res == NULL &&
445 pst->pst_creg.pr_rid == 0 &&
446 pst->pst_creg.pr_gas.SpaceId ==
447 ACPI_ADR_SPACE_FIXED_HARDWARE &&
448 pst->pst_sreg.pr_res == NULL &&
449 pst->pst_sreg.pr_rid == 0 &&
450 pst->pst_sreg.pr_gas.SpaceId ==
451 ACPI_ADR_SPACE_FIXED_HARDWARE) {
452 sc->pst_creg = pst->pst_creg;
453 sc->pst_sreg = pst->pst_sreg;
454 device_printf(dev,
455 "No _PCT; reuse %s control/status regs\n",
456 device_get_nameunit(pst->pst_dev));
457 goto fetch_pss;
458 }
c3a2c0df
SZ
459 device_printf(dev, "Can't get _PCT package - %s\n",
460 AcpiFormatException(status));
461 return ENXIO;
462 }
463
464 obj = (ACPI_OBJECT *)buf.Pointer;
465 if (!ACPI_PKG_VALID_EQ(obj, 2)) {
466 device_printf(dev, "Invalid _PCT package\n");
467 AcpiOsFree(obj);
468 return ENXIO;
469 }
470
0e276230
SZ
471 /* Save and try allocating control register */
472 error = acpi_pst_alloc_resource(dev, obj, 0, &sc->pst_creg);
76418417
SZ
473 if (error) {
474 AcpiOsFree(obj);
475 return error;
476 }
c3a2c0df 477 if (bootverbose) {
b6b64e7b 478 device_printf(dev, "control reg %d %jx\n",
10f97674 479 sc->pst_creg.pr_gas.SpaceId,
b6b64e7b 480 (uintmax_t)sc->pst_creg.pr_gas.Address);
c3a2c0df
SZ
481 }
482
0e276230
SZ
483 /* Save and try allocating status register */
484 error = acpi_pst_alloc_resource(dev, obj, 1, &sc->pst_sreg);
76418417
SZ
485 if (error) {
486 AcpiOsFree(obj);
487 return error;
488 }
c3a2c0df 489 if (bootverbose) {
b6b64e7b 490 device_printf(dev, "status reg %d %jx\n",
76418417 491 sc->pst_sreg.pr_gas.SpaceId,
b6b64e7b 492 (uintmax_t)sc->pst_sreg.pr_gas.Address);
c3a2c0df
SZ
493 }
494
495 /* Free _PCT */
496 AcpiOsFree(obj);
497
6ac1e346 498fetch_pss:
c3a2c0df
SZ
499 /*
500 * Create P-State table according to _PSS
501 */
502 buf.Pointer = NULL;
503 buf.Length = ACPI_ALLOCATE_BUFFER;
504 status = AcpiEvaluateObject(sc->pst_handle, "_PSS", NULL, &buf);
505 if (ACPI_FAILURE(status)) {
6ac1e346
SZ
506 /*
507 * No _PSS. See the comment in acpi_pst_probe() near
508 * _PSD check.
509 *
510 * Assume _PSS are same across all CPUs; well, they
511 * should/have to be so.
512 */
513 if (acpi_npstates > 0 && acpi_pstates != NULL) {
514 device_printf(dev, "No _PSS\n");
515 goto fetch_ppc;
516 }
c3a2c0df
SZ
517 device_printf(dev, "Can't get _PSS package - %s\n",
518 AcpiFormatException(status));
519 return ENXIO;
520 }
521
522 obj = (ACPI_OBJECT *)buf.Pointer;
523 if (!ACPI_PKG_VALID(obj, 1)) {
524 device_printf(dev, "Invalid _PSS package\n");
525 AcpiOsFree(obj);
526 return ENXIO;
527 }
528
529 /* Don't create too many P-States */
530 npstate = obj->Package.Count;
531 if (npstate > ACPI_NPSTATE_MAX) {
532 device_printf(dev, "Too many P-States, %d->%d\n",
533 npstate, ACPI_NPSTATE_MAX);
534 npstate = ACPI_NPSTATE_MAX;
535 }
536
537 /*
538 * If we have already created P-State table,
539 * we must make sure that number of entries
540 * is consistent.
541 */
542 if (acpi_pstates != NULL && acpi_npstates != npstate) {
543 device_printf(dev, "Inconsistent # of P-States "
544 "cross Processor objects\n");
545 AcpiOsFree(obj);
546 return ENXIO;
547 }
548
549 /*
550 * Create a temporary P-State table
551 */
552 pstate = kmalloc(sizeof(*pstate) * npstate, M_TEMP, M_WAITOK);
553 for (i = 0, p = pstate; i < npstate; ++i, ++p) {
554 ACPI_OBJECT *pkg;
555 uint32_t *ptr[ACPI_PSS_PX_NENTRY] = {
556 &p->st_freq, &p->st_power, &p->st_xsit_lat,
557 &p->st_bm_lat, &p->st_cval, &p->st_sval
558 };
559 int j;
560
561 pkg = &obj->Package.Elements[i];
562 if (!ACPI_PKG_VALID(pkg, ACPI_PSS_PX_NENTRY)) {
563 device_printf(dev, "Invalud _PSS P%d\n", i);
564 AcpiOsFree(obj);
565 kfree(pstate, M_TEMP);
566 return ENXIO;
567 }
568 for (j = 0; j < ACPI_PSS_PX_NENTRY; ++j) {
569 if (acpi_PkgInt32(pkg, j, ptr[j]) != 0) {
570 device_printf(dev, "Can't extract "
571 "_PSS P%d %dth entry\n", i, j);
572 AcpiOsFree(obj);
573 kfree(pstate, M_TEMP);
574 return ENXIO;
575 }
576 }
577 }
578
579 /* Free _PSS */
580 AcpiOsFree(obj);
581
582 if (acpi_pstates == NULL) {
583 /*
584 * If no P-State table is created yet,
585 * save the temporary one we just created.
586 */
587 acpi_pstates = pstate;
588 acpi_npstates = npstate;
589 pstate = NULL;
590
591 if (bootverbose) {
592 for (i = 0; i < acpi_npstates; ++i) {
593 device_printf(dev,
594 "freq %u, pwr %u, xlat %u, blat %u, "
595 "cv %08x, sv %08x\n",
596 acpi_pstates[i].st_freq,
597 acpi_pstates[i].st_power,
598 acpi_pstates[i].st_xsit_lat,
599 acpi_pstates[i].st_bm_lat,
600 acpi_pstates[i].st_cval,
601 acpi_pstates[i].st_sval);
602 }
603 }
604 } else {
605 /*
606 * Make sure that P-State tables are same
607 * for all processors.
608 */
609 if (memcmp(pstate, acpi_pstates,
610 sizeof(*pstate) * npstate) != 0) {
611 device_printf(dev, "Inconsistent _PSS "
612 "cross Processor objects\n");
3dc86a14
SZ
613#if 0
614 /*
615 * Some BIOSes create different P-State tables;
616 * just trust the one from the BSP and move on.
617 */
c3a2c0df
SZ
618 kfree(pstate, M_TEMP);
619 return ENXIO;
3dc86a14 620#endif
c3a2c0df
SZ
621 }
622 kfree(pstate, M_TEMP);
623 }
624
6ac1e346 625fetch_ppc:
c3a2c0df 626 /* By default, we start from P-State table's first entry */
15e3104c 627 sstart = 0;
c3a2c0df
SZ
628
629 /*
630 * Adjust the usable first entry of P-State table,
631 * if there is _PPC object.
632 */
633 buf.Pointer = NULL;
634 buf.Length = ACPI_ALLOCATE_BUFFER;
635 status = AcpiEvaluateObject(sc->pst_handle, "_PPC", NULL, &buf);
636 if (!ACPI_FAILURE(status)) {
1a2cf7fd
SZ
637 ACPI_OBJECT_LIST arglist;
638 ACPI_OBJECT arg[2];
639
c3a2c0df
SZ
640 obj = (ACPI_OBJECT *)buf.Pointer;
641 if (obj->Type == ACPI_TYPE_INTEGER) {
642 if (obj->Integer.Value >= acpi_npstates) {
643 device_printf(dev, "Invalid _PPC value\n");
644 AcpiOsFree(obj);
645 return ENXIO;
646 }
15e3104c 647 sstart = obj->Integer.Value;
c3a2c0df 648 if (bootverbose)
15e3104c 649 device_printf(dev, "_PPC %d\n", sstart);
c3a2c0df
SZ
650
651 /* TODO: Install notifiy handler */
652 } else {
653 device_printf(dev, "Invalid _PPC object\n");
654 AcpiOsFree(obj);
655 return ENXIO;
656 }
657
658 /* Free _PPC */
659 AcpiOsFree(obj);
1a2cf7fd
SZ
660
661 /* _PPC has been successfully processed */
662 arglist.Pointer = arg;
663 arglist.Count = 2;
664 arg[0].Type = ACPI_TYPE_INTEGER;
665 arg[0].Integer.Value = 0x80;
666 arg[1].Type = ACPI_TYPE_INTEGER;
667 arg[1].Integer.Value = 0;
668 AcpiEvaluateObject(sc->pst_handle, "_OST", &arglist, NULL);
c3a2c0df 669 }
15e3104c
SZ
670 if (acpi_pstate_start < 0) {
671 acpi_pstate_start = sstart;
672 } else if (acpi_pstate_start != sstart) {
673 device_printf(dev, "_PPC mismatch, was %d, now %d\n",
674 acpi_pstate_start, sstart);
675 if (acpi_pstate_start < sstart) {
676 device_printf(dev, "_PPC %d -> %d\n",
677 acpi_pstate_start, sstart);
678 acpi_pstate_start = sstart;
679 }
680 }
c3a2c0df 681
c8676324
SZ
682 /*
683 * By default, we assume number of usable P-States is same as
684 * number of P-States.
685 */
686 scount = acpi_npstates;
687
8ca16411
SZ
688 /*
689 * Allow users to override or set _PDL
690 */
691 if (acpi_pst_pdl >= 0) {
692 if (acpi_pst_pdl < acpi_npstates) {
693 if (bootverbose) {
694 device_printf(dev, "_PDL override %d\n",
695 acpi_pst_pdl);
696 }
697 scount = acpi_pst_pdl + 1;
698 goto proc_pdl;
699 } else {
700 device_printf(dev, "Invalid _PDL override %d, "
701 "must be less than %d\n", acpi_pst_pdl,
702 acpi_npstates);
703 }
704 }
705
c8676324
SZ
706 /*
707 * Adjust the number of usable entries in P-State table,
708 * if there is _PDL object.
709 */
710 buf.Pointer = NULL;
711 buf.Length = ACPI_ALLOCATE_BUFFER;
712 status = AcpiEvaluateObject(sc->pst_handle, "_PDL", NULL, &buf);
713 if (!ACPI_FAILURE(status)) {
714 obj = (ACPI_OBJECT *)buf.Pointer;
715 if (obj->Type == ACPI_TYPE_INTEGER) {
716 if (obj->Integer.Value >= acpi_npstates) {
717 device_printf(dev, "Invalid _PDL value\n");
718 AcpiOsFree(obj);
719 return ENXIO;
720 }
721 if (obj->Integer.Value >= acpi_pstate_start) {
722 scount = obj->Integer.Value + 1;
723 if (bootverbose)
724 device_printf(dev, "_PDL %d\n", scount);
725 } else {
726 /* Prefer _PPC as stated in ACPI 5.1 8.4.4.6 */
727 device_printf(dev, "conflict _PDL %ju and "
728 "_PPC %d, ignore\n",
729 (uintmax_t)obj->Integer.Value,
730 acpi_pstate_start);
731 }
732
733 /* TODO: Install notifiy handler */
734 } else {
735 device_printf(dev, "Invalid _PDL object\n");
736 AcpiOsFree(obj);
737 return ENXIO;
738 }
739
740 /* Free _PDL */
741 AcpiOsFree(obj);
742 }
8ca16411 743proc_pdl:
c8676324
SZ
744 if (acpi_pstate_count == 0) {
745 acpi_pstate_count = scount;
746 } else if (acpi_pstate_count != scount) {
747 device_printf(dev, "_PDL mismatch, was %d, now %d\n",
748 acpi_pstate_count, scount);
749 if (acpi_pstate_count > scount) {
750 device_printf(dev, "_PDL %d -> %d\n",
751 acpi_pstate_count, scount);
752 acpi_pstate_count = scount;
753 }
754 }
755
dbe50d54
SZ
756 /*
757 * Some CPUs only have package P-states, but some BIOSes put each
758 * hyperthread to its own P-state domain; allow user to override.
759 */
760 if (LIST_EMPTY(&dom->pd_pstlist) && acpi_pst_force_pkg_domain) {
761 cpumask_t mask;
762
763 mask = get_cpumask_from_level(sc->pst_cpuid, CHIP_LEVEL);
764 if (CPUMASK_TESTNZERO(mask)) {
765 struct acpi_pst_softc *pst = NULL;
766 struct acpi_pst_domain *dom1;
767
768 LIST_FOREACH(dom1, &acpi_pst_domains, pd_link) {
769 LIST_FOREACH(pst, &dom1->pd_pstlist,
770 pst_link) {
771 if (CPUMASK_TESTBIT(mask,
772 pst->pst_cpuid))
773 break;
774 }
775 if (pst != NULL)
776 break;
777 }
778 if (pst != NULL &&
779 memcmp(&pst->pst_creg, &sc->pst_creg,
780 sizeof(sc->pst_creg)) == 0 &&
781 memcmp(&pst->pst_sreg, &sc->pst_sreg,
782 sizeof(sc->pst_sreg)) == 0) {
783 /*
784 * Use the same domain for CPUs in the
785 * same package.
786 */
787 device_printf(dev, "Destroy domain%u, "
788 "force pkg domain%u\n",
789 dom->pd_dom, dom1->pd_dom);
790 LIST_REMOVE(dom, pd_link);
791 kfree(dom, M_DEVBUF);
792 dom = dom1;
793 /*
794 * Make sure that adding us will not
795 * overflow the domain containing
796 * siblings in the same package.
797 */
798 acpi_pst_domain_check_nproc(dev, dom);
799 }
800 }
801 }
802
c3a2c0df
SZ
803 /* Link us with the domain */
804 sc->pst_domain = dom;
805 LIST_INSERT_HEAD(&dom->pd_pstlist, sc, pst_link);
806
807 if (device_get_unit(dev) == 0)
808 AcpiOsExecute(OSL_NOTIFY_HANDLER, acpi_pst_postattach, NULL);
809
810 return 0;
811}
812
813static struct acpi_pst_domain *
0cb292d1 814acpi_pst_domain_create_pkg(device_t dev, ACPI_OBJECT *obj)
c3a2c0df
SZ
815{
816 struct acpi_pst_domain *dom;
817 uint32_t val, domain, coord, nproc;
818
819 if (!ACPI_PKG_VALID_EQ(obj, 5)) {
820 device_printf(dev, "Invalid _PSD package\n");
821 return NULL;
822 }
823
824 /* NumberOfEntries */
825 if (acpi_PkgInt32(obj, 0, &val) != 0 || val != 5) {
826 device_printf(dev, "Invalid _PSD NumberOfEntries\n");
827 return NULL;
828 }
829
830 /* Revision */
831 if (acpi_PkgInt32(obj, 1, &val) != 0 || val != 0) {
832 device_printf(dev, "Invalid _PSD Revision\n");
833 return NULL;
834 }
835
836 if (acpi_PkgInt32(obj, 2, &domain) != 0 ||
837 acpi_PkgInt32(obj, 3, &coord) != 0 ||
838 acpi_PkgInt32(obj, 4, &nproc) != 0) {
839 device_printf(dev, "Can't extract _PSD package\n");
840 return NULL;
841 }
842
2f336f65
SZ
843 if (!ACPI_PSD_COORD_VALID(coord)) {
844 device_printf(dev, "Invalid _PSD CoordType (%#x)\n", coord);
c3a2c0df
SZ
845 return NULL;
846 }
847
2f336f65
SZ
848 if (nproc > MAXCPU) {
849 /*
850 * If NumProcessors is greater than MAXCPU
851 * and domain's coordination is SWALL, then
852 * we will never be able to start all CPUs
853 * within this domain, and power state
854 * transition will never be completed, so we
855 * just bail out here.
856 */
857 if (coord == ACPI_PSD_COORD_SWALL) {
858 device_printf(dev, "Unsupported _PSD NumProcessors "
859 "(%d)\n", nproc);
860 return NULL;
861 }
862 } else if (nproc == 0) {
863 device_printf(dev, "_PSD NumProcessors are zero\n");
c3a2c0df
SZ
864 return NULL;
865 }
866
867 dom = acpi_pst_domain_find(domain);
868 if (dom != NULL) {
0cb292d1
SZ
869 if (dom->pd_flags & ACPI_PSTDOM_FLAG_INT) {
870 device_printf(dev, "Mixed Integer _PSD and "
871 "Package _PSD\n");
872 return NULL;
873 }
aedb11c5
SZ
874 if (dom->pd_coord != coord) {
875 device_printf(dev, "Inconsistent _PSD coord "
876 "information cross Processor objects\n");
c3a2c0df
SZ
877 return NULL;
878 }
aedb11c5
SZ
879 if (dom->pd_nproc != nproc) {
880 device_printf(dev, "Inconsistent _PSD nproc "
881 "information cross Processor objects\n");
882 /*
883 * Some stupid BIOSes will set wrong "# of processors",
884 * e.g. 1 for CPU w/ hyperthreading; Be lenient here.
885 */
886 }
c3a2c0df
SZ
887 return dom;
888 }
889
890 dom = acpi_pst_domain_alloc(domain, coord, nproc);
95b6142f
SZ
891 if (bootverbose) {
892 device_printf(dev, "create pkg domain%u, coord %#x\n",
893 dom->pd_dom, dom->pd_coord);
894 }
0cb292d1
SZ
895
896 return dom;
897}
898
899static struct acpi_pst_domain *
900acpi_pst_domain_create_int(device_t dev, uint32_t domain)
901{
902 struct acpi_pst_domain *dom;
903
904 dom = acpi_pst_domain_find(domain);
905 if (dom != NULL) {
906 if ((dom->pd_flags & ACPI_PSTDOM_FLAG_INT) == 0) {
907 device_printf(dev, "Mixed Package _PSD and "
908 "Integer _PSD\n");
909 return NULL;
910 }
911 KKASSERT(dom->pd_coord == ACPI_PSD_COORD_SWALL);
912
913 dom->pd_nproc++;
914 return dom;
915 }
916
917 dom = acpi_pst_domain_alloc(domain, ACPI_PSD_COORD_SWALL, 1);
918 dom->pd_flags |= ACPI_PSTDOM_FLAG_INT;
919
920 if (bootverbose)
921 device_printf(dev, "create int domain%u\n", dom->pd_dom);
c3a2c0df
SZ
922
923 return dom;
924}
925
926static struct acpi_pst_domain *
927acpi_pst_domain_find(uint32_t domain)
928{
929 struct acpi_pst_domain *dom;
930
931 LIST_FOREACH(dom, &acpi_pst_domains, pd_link) {
932 if (dom->pd_flags & ACPI_PSTDOM_FLAG_STUB)
933 continue;
934 if (dom->pd_dom == domain)
935 return dom;
936 }
937 return NULL;
938}
939
940static struct acpi_pst_domain *
941acpi_pst_domain_alloc(uint32_t domain, uint32_t coord, uint32_t nproc)
942{
943 struct acpi_pst_domain *dom;
944
945 dom = kmalloc(sizeof(*dom), M_DEVBUF, M_WAITOK | M_ZERO);
946 dom->pd_dom = domain;
947 dom->pd_coord = coord;
948 dom->pd_nproc = nproc;
c3a2c0df
SZ
949 LIST_INIT(&dom->pd_pstlist);
950
951 LIST_INSERT_HEAD(&acpi_pst_domains, dom, pd_link);
952
953 return dom;
954}
955
7b46b972
SZ
956static int
957acpi_pst_domain_set_pstate(struct acpi_pst_domain *dom, int i)
958{
959 const struct acpi_pstate *pstate;
960 struct acpi_pst_softc *sc;
961 int done, error;
962
963 KKASSERT(i >= 0 && i < acpi_npstates);
964 pstate = &acpi_pstates[i];
965
966 done = 0;
967 LIST_FOREACH(sc, &dom->pd_pstlist, pst_link) {
968 if (!done) {
969 error = acpi_pst_set_pstate(sc, pstate);
970 if (error) {
971 device_printf(sc->pst_dev, "can't set "
972 "freq %d\n", pstate->st_freq);
973 /* XXX error cleanup? */
974 }
975 if (dom->pd_coord == ACPI_PSD_COORD_SWANY)
976 done = 1;
977 }
978 sc->pst_state = i;
979 }
980 dom->pd_state = i;
981
982 return 0;
983}
984
446b8384
SZ
985static int
986acpi_pst_global_set_pstate(int i)
987{
988 struct acpi_pst_domain *dom;
989
990 LIST_FOREACH(dom, &acpi_pst_domains, pd_link) {
991 /* Skip dead domain */
992 if (dom->pd_flags & ACPI_PSTDOM_FLAG_DEAD)
993 continue;
994 acpi_pst_domain_set_pstate(dom, i);
995 }
996 acpi_pst_global_state = i;
997
998 return 0;
999}
1000
c3a2c0df
SZ
1001static void
1002acpi_pst_postattach(void *arg __unused)
1003{
1004 struct acpi_pst_domain *dom;
41d9045e 1005 struct acpi_cpu_softc *cpu;
c3a2c0df 1006 device_t *devices;
15e3104c 1007 int i, ndevices, error, has_domain;
c3a2c0df
SZ
1008
1009 devices = NULL;
1010 ndevices = 0;
7b46b972
SZ
1011 error = devclass_get_devices(acpi_pst_devclass, &devices, &ndevices);
1012 if (error)
1013 return;
1014
c3a2c0df
SZ
1015 if (ndevices == 0)
1016 return;
1017
41d9045e 1018 cpu = NULL;
c3a2c0df 1019 for (i = 0; i < ndevices; ++i) {
41d9045e
SZ
1020 cpu = device_get_softc(device_get_parent(devices[i]));
1021 if (cpu->glob_sysctl_tree != NULL)
c3a2c0df
SZ
1022 break;
1023 }
1024 kfree(devices, M_TEMP);
41d9045e 1025 KKASSERT(cpu != NULL);
c3a2c0df 1026
7b46b972
SZ
1027 if (acpi_pst_md == NULL)
1028 kprintf("ACPI: no P-State CPU driver\n");
1029
1030 has_domain = 0;
c3a2c0df
SZ
1031 LIST_FOREACH(dom, &acpi_pst_domains, pd_link) {
1032 struct acpi_pst_softc *sc;
1033 char buf[32];
1034
15e3104c
SZ
1035 dom->pd_state = acpi_pstate_start;
1036
7b46b972
SZ
1037 /*
1038 * Make sure that all processors belonging to this
1039 * domain are located.
1040 */
c3a2c0df 1041 i = 0;
15e3104c
SZ
1042 LIST_FOREACH(sc, &dom->pd_pstlist, pst_link) {
1043 sc->pst_state = acpi_pstate_start;
c3a2c0df 1044 ++i;
15e3104c 1045 }
c3a2c0df 1046 if (i != dom->pd_nproc) {
2f336f65
SZ
1047 KKASSERT(i < dom->pd_nproc);
1048
7b46b972
SZ
1049 kprintf("ACPI: domain%u misses processors, "
1050 "should be %d, got %d\n", dom->pd_dom,
1051 dom->pd_nproc, i);
2f336f65
SZ
1052 if (dom->pd_coord == ACPI_PSD_COORD_SWALL) {
1053 /*
1054 * If this domain's coordination is
1055 * SWALL and we don't see all of the
1056 * member CPUs of this domain, then
1057 * the P-State transition will never
1058 * be completed, so just leave this
1059 * domain out.
1060 */
1061 dom->pd_flags |= ACPI_PSTDOM_FLAG_DEAD;
1062 continue;
1063 }
1064 dom->pd_nproc = i;
7b46b972
SZ
1065 }
1066
1067 /*
1068 * Validate P-State configurations for this domain
1069 */
1070 LIST_FOREACH(sc, &dom->pd_pstlist, pst_link) {
1071 error = acpi_pst_check_csr(sc);
1072 if (error)
1073 break;
1074
1075 error = acpi_pst_check_pstates(sc);
1076 if (error)
1077 break;
1078 }
1079 if (sc != NULL) {
1080 kprintf("ACPI: domain%u P-State configuration "
1081 "check failed\n", dom->pd_dom);
1082 dom->pd_flags |= ACPI_PSTDOM_FLAG_DEAD;
c3a2c0df
SZ
1083 continue;
1084 }
7b46b972 1085
c5479e60
SZ
1086 /*
1087 * Do necssary P-State initialization
1088 */
1089 LIST_FOREACH(sc, &dom->pd_pstlist, pst_link) {
1090 error = acpi_pst_init(sc);
1091 if (error)
1092 break;
1093 }
1094 if (sc != NULL) {
1095 kprintf("ACPI: domain%u P-State initialization "
1096 "check failed\n", dom->pd_dom);
1097 dom->pd_flags |= ACPI_PSTDOM_FLAG_DEAD;
1098 continue;
1099 }
1100
7b46b972
SZ
1101 has_domain = 1;
1102
c3a2c0df
SZ
1103 ksnprintf(buf, sizeof(buf), "px_dom%u", dom->pd_dom);
1104
1105 sysctl_ctx_init(&dom->pd_sysctl_ctx);
1106 dom->pd_sysctl_tree =
1107 SYSCTL_ADD_NODE(&dom->pd_sysctl_ctx,
41d9045e 1108 SYSCTL_CHILDREN(cpu->glob_sysctl_tree),
c3a2c0df
SZ
1109 OID_AUTO, buf, CTLFLAG_RD, 0,
1110 "P-State domain");
7b46b972
SZ
1111 if (dom->pd_sysctl_tree == NULL) {
1112 kprintf("ACPI: Can't create sysctl tree for domain%u",
1113 dom->pd_dom);
c3a2c0df 1114 continue;
7b46b972 1115 }
c3a2c0df
SZ
1116
1117 SYSCTL_ADD_PROC(&dom->pd_sysctl_ctx,
1118 SYSCTL_CHILDREN(dom->pd_sysctl_tree),
1119 OID_AUTO, "available",
df29c611 1120 CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_SKIP,
c3a2c0df
SZ
1121 dom, 0, acpi_pst_sysctl_freqs, "A",
1122 "available frequencies");
1123
1555fc97
SZ
1124 SYSCTL_ADD_PROC(&dom->pd_sysctl_ctx,
1125 SYSCTL_CHILDREN(dom->pd_sysctl_tree),
df29c611 1126 OID_AUTO, "avail",
1555fc97
SZ
1127 CTLTYPE_OPAQUE | CTLFLAG_RD,
1128 dom, 0, acpi_pst_sysctl_freqs_bin, "IU",
df29c611 1129 "available frequencies");
1555fc97 1130
c3a2c0df
SZ
1131 SYSCTL_ADD_PROC(&dom->pd_sysctl_ctx,
1132 SYSCTL_CHILDREN(dom->pd_sysctl_tree),
1133 OID_AUTO, "members",
1134 CTLTYPE_STRING | CTLFLAG_RD,
1135 dom, 0, acpi_pst_sysctl_members, "A",
1136 "member cpus");
7b46b972
SZ
1137
1138 if (acpi_pst_md != NULL &&
1139 acpi_pst_md->pmd_set_pstate != NULL) {
1140 SYSCTL_ADD_PROC(&dom->pd_sysctl_ctx,
1141 SYSCTL_CHILDREN(dom->pd_sysctl_tree),
1142 OID_AUTO, "select",
1143 CTLTYPE_UINT | CTLFLAG_RW,
1144 dom, 0, acpi_pst_sysctl_select,
1145 "IU", "select freq");
1146 }
1147 }
1148
1149 if (has_domain && acpi_pst_md != NULL &&
1150 acpi_pst_md->pmd_set_pstate != NULL) {
41d9045e
SZ
1151 SYSCTL_ADD_PROC(&cpu->glob_sysctl_ctx,
1152 SYSCTL_CHILDREN(cpu->glob_sysctl_tree),
7b46b972
SZ
1153 OID_AUTO, "px_global",
1154 CTLTYPE_UINT | CTLFLAG_RW,
1155 NULL, 0, acpi_pst_sysctl_global,
1156 "IU", "select freq for all domains");
446b8384 1157
15e3104c 1158 acpi_pst_global_set_pstate(acpi_pstate_start);
c3a2c0df
SZ
1159 }
1160}
1161
1162static int
1163acpi_pst_sysctl_freqs(SYSCTL_HANDLER_ARGS)
1164{
c3a2c0df
SZ
1165 int i, error;
1166
1167 error = 0;
1168 for (i = 0; i < acpi_npstates; ++i) {
1169 if (error == 0 && i)
1170 error = SYSCTL_OUT(req, " ", 1);
1171 if (error == 0) {
1172 const char *pat;
1173 char buf[32];
1174
c8676324 1175 if (i < acpi_pstate_start || i >= acpi_pstate_count)
c3a2c0df
SZ
1176 pat = "(%u)";
1177 else
1178 pat = "%u";
1179
1180 ksnprintf(buf, sizeof(buf), pat,
1181 acpi_pstates[i].st_freq);
1182 error = SYSCTL_OUT(req, buf, strlen(buf));
1183 }
1184 }
1185 return error;
1186}
1187
1555fc97
SZ
1188static int
1189acpi_pst_sysctl_freqs_bin(SYSCTL_HANDLER_ARGS)
1190{
1555fc97
SZ
1191 uint32_t freqs[ACPI_NPSTATE_MAX];
1192 int cnt, i;
1193
c8676324 1194 cnt = acpi_pstate_count - acpi_pstate_start;
1555fc97 1195 for (i = 0; i < cnt; ++i)
15e3104c 1196 freqs[i] = acpi_pstates[acpi_pstate_start + i].st_freq;
1555fc97
SZ
1197
1198 return sysctl_handle_opaque(oidp, freqs, cnt * sizeof(freqs[0]), req);
1199}
1200
c3a2c0df
SZ
1201static int
1202acpi_pst_sysctl_members(SYSCTL_HANDLER_ARGS)
1203{
1204 struct acpi_pst_domain *dom = arg1;
7b46b972 1205 struct acpi_pst_softc *sc;
c3a2c0df
SZ
1206 int loop, error;
1207
1208 loop = error = 0;
1209 LIST_FOREACH(sc, &dom->pd_pstlist, pst_link) {
7b46b972
SZ
1210 char buf[32];
1211
c3a2c0df
SZ
1212 if (error == 0 && loop)
1213 error = SYSCTL_OUT(req, " ", 1);
1214 if (error == 0) {
c3a2c0df
SZ
1215 ksnprintf(buf, sizeof(buf), "cpu%d", sc->pst_cpuid);
1216 error = SYSCTL_OUT(req, buf, strlen(buf));
1217 }
7b46b972
SZ
1218
1219 if (error == 0 && acpi_pst_md && acpi_pst_md->pmd_get_pstate) {
1220 const struct acpi_pstate *pstate;
1221 const char *str;
1222
1223 pstate = acpi_pst_get_pstate(sc);
1224 if (pstate == NULL) {
1225 str = "(*)";
1226 } else {
1227 ksnprintf(buf, sizeof(buf), "(%d)",
1228 pstate->st_freq);
1229 str = buf;
1230 }
1231 error = SYSCTL_OUT(req, str, strlen(str));
1232 }
c3a2c0df
SZ
1233 ++loop;
1234 }
1235 return error;
1236}
7b46b972
SZ
1237
1238static int
1239acpi_pst_sysctl_select(SYSCTL_HANDLER_ARGS)
1240{
1241 struct acpi_pst_domain *dom = arg1;
1242 int error, i, freq;
1243
1244 KKASSERT(dom->pd_state >= 0 && dom->pd_state < acpi_npstates);
1245
1246 freq = acpi_pstates[dom->pd_state].st_freq;
1247
1248 error = sysctl_handle_int(oidp, &freq, 0, req);
1249 if (error || req->newptr == NULL)
1250 return error;
1251
1252 i = acpi_pst_freq2index(freq);
1253 if (i < 0)
1254 return EINVAL;
1255
1256 acpi_pst_domain_set_pstate(dom, i);
1257 return 0;
1258}
1259
1260static int
1261acpi_pst_sysctl_global(SYSCTL_HANDLER_ARGS)
1262{
7b46b972
SZ
1263 int error, i, freq;
1264
1265 KKASSERT(acpi_pst_global_state >= 0 &&
1266 acpi_pst_global_state < acpi_npstates);
1267
1268 freq = acpi_pstates[acpi_pst_global_state].st_freq;
1269
1270 error = sysctl_handle_int(oidp, &freq, 0, req);
1271 if (error || req->newptr == NULL)
1272 return error;
1273
1274 i = acpi_pst_freq2index(freq);
1275 if (i < 0)
1276 return EINVAL;
1277
446b8384 1278 acpi_pst_global_set_pstate(i);
7b46b972
SZ
1279
1280 return 0;
1281}
1282
1283static void
002c1265 1284acpi_pst_check_csr_handler(netmsg_t msg)
7b46b972 1285{
002c1265 1286 struct netmsg_acpi_pst *rmsg = (struct netmsg_acpi_pst *)msg;
7b46b972
SZ
1287 int error;
1288
002c1265
MD
1289 error = acpi_pst_md->pmd_check_csr(rmsg->ctrl, rmsg->status);
1290 lwkt_replymsg(&rmsg->base.lmsg, error);
7b46b972
SZ
1291}
1292
1293static int
1294acpi_pst_check_csr(struct acpi_pst_softc *sc)
1295{
1296 struct netmsg_acpi_pst msg;
1297
1298 if (acpi_pst_md == NULL)
1299 return 0;
1300
002c1265 1301 netmsg_init(&msg.base, NULL, &curthread->td_msgport,
c3c96e44 1302 MSGF_PRIORITY, acpi_pst_check_csr_handler);
7b46b972
SZ
1303 msg.ctrl = &sc->pst_creg;
1304 msg.status = &sc->pst_sreg;
1305
ec7f7fc8 1306 return lwkt_domsg(netisr_cpuport(sc->pst_cpuid), &msg.base.lmsg, 0);
7b46b972
SZ
1307}
1308
1309static void
002c1265 1310acpi_pst_check_pstates_handler(netmsg_t msg)
7b46b972
SZ
1311{
1312 int error;
1313
1314 error = acpi_pst_md->pmd_check_pstates(acpi_pstates, acpi_npstates);
002c1265 1315 lwkt_replymsg(&msg->lmsg, error);
7b46b972
SZ
1316}
1317
1318static int
1319acpi_pst_check_pstates(struct acpi_pst_softc *sc)
1320{
002c1265 1321 struct netmsg_base msg;
7b46b972
SZ
1322
1323 if (acpi_pst_md == NULL)
1324 return 0;
1325
002c1265 1326 netmsg_init(&msg, NULL, &curthread->td_msgport,
c3c96e44 1327 MSGF_PRIORITY, acpi_pst_check_pstates_handler);
7b46b972 1328
ec7f7fc8 1329 return lwkt_domsg(netisr_cpuport(sc->pst_cpuid), &msg.lmsg, 0);
7b46b972
SZ
1330}
1331
c5479e60 1332static void
002c1265 1333acpi_pst_init_handler(netmsg_t msg)
c5479e60 1334{
002c1265 1335 struct netmsg_acpi_pst *rmsg = (struct netmsg_acpi_pst *)msg;
c5479e60
SZ
1336 int error;
1337
002c1265
MD
1338 error = acpi_pst_md->pmd_init(rmsg->ctrl, rmsg->status);
1339 lwkt_replymsg(&rmsg->base.lmsg, error);
c5479e60
SZ
1340}
1341
1342static int
1343acpi_pst_init(struct acpi_pst_softc *sc)
1344{
1345 struct netmsg_acpi_pst msg;
1346
1347 if (acpi_pst_md == NULL)
1348 return 0;
1349
002c1265 1350 netmsg_init(&msg.base, NULL, &curthread->td_msgport,
c3c96e44 1351 MSGF_PRIORITY, acpi_pst_init_handler);
c5479e60
SZ
1352 msg.ctrl = &sc->pst_creg;
1353 msg.status = &sc->pst_sreg;
1354
ec7f7fc8 1355 return lwkt_domsg(netisr_cpuport(sc->pst_cpuid), &msg.base.lmsg, 0);
c5479e60
SZ
1356}
1357
7b46b972 1358static void
002c1265 1359acpi_pst_set_pstate_handler(netmsg_t msg)
7b46b972 1360{
002c1265 1361 struct netmsg_acpi_pst *rmsg = (struct netmsg_acpi_pst *)msg;
7b46b972
SZ
1362 int error;
1363
002c1265
MD
1364 error = acpi_pst_md->pmd_set_pstate(rmsg->ctrl, rmsg->status,
1365 rmsg->base.lmsg.u.ms_resultp);
1366 lwkt_replymsg(&rmsg->base.lmsg, error);
7b46b972
SZ
1367}
1368
1369static int
1370acpi_pst_set_pstate(struct acpi_pst_softc *sc, const struct acpi_pstate *pstate)
1371{
1372 struct netmsg_acpi_pst msg;
1373
1374 KKASSERT(acpi_pst_md != NULL);
1375
002c1265 1376 netmsg_init(&msg.base, NULL, &curthread->td_msgport,
c3c96e44 1377 MSGF_PRIORITY, acpi_pst_set_pstate_handler);
002c1265 1378 msg.base.lmsg.u.ms_resultp = __DECONST(void *, pstate);
7b46b972
SZ
1379 msg.ctrl = &sc->pst_creg;
1380 msg.status = &sc->pst_sreg;
1381
ec7f7fc8 1382 return lwkt_domsg(netisr_cpuport(sc->pst_cpuid), &msg.base.lmsg, 0);
7b46b972
SZ
1383}
1384
1385static void
002c1265 1386acpi_pst_get_pstate_handler(netmsg_t msg)
7b46b972 1387{
002c1265 1388 struct netmsg_acpi_pst *rmsg = (struct netmsg_acpi_pst *)msg;
7b46b972
SZ
1389 const struct acpi_pstate *pstate;
1390
002c1265 1391 pstate = acpi_pst_md->pmd_get_pstate(rmsg->status, acpi_pstates,
7b46b972 1392 acpi_npstates);
002c1265
MD
1393 rmsg->base.lmsg.u.ms_resultp = __DECONST(void *, pstate);
1394 lwkt_replymsg(&rmsg->base.lmsg, 0);
7b46b972
SZ
1395}
1396
1397static const struct acpi_pstate *
1398acpi_pst_get_pstate(struct acpi_pst_softc *sc)
1399{
1400 struct netmsg_acpi_pst msg;
1401
1402 if (acpi_pst_md == NULL)
1403 return 0;
1404
002c1265 1405 netmsg_init(&msg.base, NULL, &curthread->td_msgport,
c3c96e44 1406 MSGF_PRIORITY, acpi_pst_get_pstate_handler);
7b46b972
SZ
1407 msg.status = &sc->pst_sreg;
1408
ec7f7fc8 1409 lwkt_domsg(netisr_cpuport(sc->pst_cpuid), &msg.base.lmsg, 0);
002c1265 1410 return msg.base.lmsg.u.ms_resultp;
7b46b972 1411}
0e276230
SZ
1412
1413static int
1414acpi_pst_alloc_resource(device_t dev, ACPI_OBJECT *obj, int idx,
1415 struct acpi_pst_res *res)
1416{
1417 struct acpi_pst_softc *sc = device_get_softc(dev);
10f97674 1418 int error, type;
0e276230
SZ
1419
1420 /* Save GAS */
1421 error = acpi_PkgRawGas(obj, idx, &res->pr_gas);
1422 if (error)
1423 return error;
1424
1425 /* Allocate resource, if possible */
41d9045e 1426 res->pr_rid = sc->pst_parent->cpu_next_rid;
10f97674 1427 acpi_bus_alloc_gas(dev, &type, &res->pr_rid, &res->pr_gas, &res->pr_res, 0);
0e276230 1428 if (res->pr_res != NULL) {
41d9045e 1429 sc->pst_parent->cpu_next_rid++;
0e276230
SZ
1430 res->pr_bt = rman_get_bustag(res->pr_res);
1431 res->pr_bh = rman_get_bushandle(res->pr_res);
1432 } else {
1433 res->pr_rid = 0;
1434 }
1435 return 0;
1436}
6ac1e346
SZ
1437
1438static void
1439acpi_pst_domain_check_nproc(device_t dev, struct acpi_pst_domain *dom)
1440{
1441 struct acpi_pst_softc *pst;
1442 int i;
1443
1444 i = 0;
1445 LIST_FOREACH(pst, &dom->pd_pstlist, pst_link)
1446 ++i;
1447 if (i == dom->pd_nproc) {
1448 /*
1449 * Some stupid BIOSes will set wrong "# of processors",
1450 * e.g. 1 for CPU w/ hyperthreading; Be lenient here.
1451 */
1452 if (bootverbose) {
1453 device_printf(dev, "domain%u already contains %d "
1454 "P-States\n", dom->pd_dom, dom->pd_nproc);
1455 }
1456 dom->pd_nproc++;
1457 }
1458 KKASSERT(i < dom->pd_nproc);
1459}