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