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