Merge branch 'vendor/OPENSSL'
[dragonfly.git] / sys / dev / acpica5 / 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
46 #include <net/netisr.h>
47 #include <net/netmsg2.h>
48 #include <net/if_var.h>
49
50 #include "acpi.h"
51 #include "acpivar.h"
52 #include "acpi_cpu.h"
53 #include "acpi_cpu_pstate.h"
54
55 #define ACPI_NPSTATE_MAX        16
56
57 #define ACPI_PSS_PX_NENTRY      6
58
59 #define ACPI_PSD_COORD_SWALL    0xfc
60 #define ACPI_PSD_COORD_SWANY    0xfd
61 #define ACPI_PSD_COORD_HWALL    0xfe
62 #define ACPI_PSD_COORD_VALID(coord) \
63         ((coord) == ACPI_PSD_COORD_SWALL || \
64          (coord) == ACPI_PSD_COORD_SWANY || \
65          (coord) == ACPI_PSD_COORD_HWALL)
66
67 struct acpi_pst_softc;
68 LIST_HEAD(acpi_pst_list, acpi_pst_softc);
69
70 struct netmsg_acpi_pst {
71         struct netmsg_base base;
72         const struct acpi_pst_res *ctrl;
73         const struct acpi_pst_res *status;
74 };
75
76 struct acpi_pst_domain {
77         uint32_t                pd_dom;
78         uint32_t                pd_coord;
79         uint32_t                pd_nproc;
80         LIST_ENTRY(acpi_pst_domain) pd_link;
81
82         uint32_t                pd_flags;
83
84         int                     pd_state;
85         int                     pd_sstart;
86         struct acpi_pst_list    pd_pstlist;
87
88         struct sysctl_ctx_list  pd_sysctl_ctx;
89         struct sysctl_oid       *pd_sysctl_tree;
90 };
91 LIST_HEAD(acpi_pst_domlist, acpi_pst_domain);
92
93 #define ACPI_PSTDOM_FLAG_STUB   0x1     /* stub domain, no _PSD */
94 #define ACPI_PSTDOM_FLAG_DEAD   0x2     /* domain can't be started */
95
96 struct acpi_pst_softc {
97         device_t                pst_dev;
98         struct acpi_cpux_softc  *pst_parent;
99         struct acpi_pst_domain  *pst_domain;
100         struct acpi_pst_res     pst_creg;
101         struct acpi_pst_res     pst_sreg;
102
103         int                     pst_state;
104         int                     pst_sstart;
105         int                     pst_cpuid;
106
107         ACPI_HANDLE             pst_handle;
108
109         LIST_ENTRY(acpi_pst_softc) pst_link;
110 };
111
112 static int      acpi_pst_probe(device_t dev);
113 static int      acpi_pst_attach(device_t dev);
114
115 static void     acpi_pst_postattach(void *);
116 static struct acpi_pst_domain *
117                 acpi_pst_domain_create(device_t, ACPI_OBJECT *);
118 static struct acpi_pst_domain *
119                 acpi_pst_domain_find(uint32_t);
120 static struct acpi_pst_domain *
121                 acpi_pst_domain_alloc(uint32_t, uint32_t, uint32_t);
122 static int      acpi_pst_domain_set_pstate(struct acpi_pst_domain *, int);
123 static int      acpi_pst_global_set_pstate(int);
124
125 static int      acpi_pst_check_csr(struct acpi_pst_softc *);
126 static int      acpi_pst_check_pstates(struct acpi_pst_softc *);
127 static int      acpi_pst_init(struct acpi_pst_softc *);
128 static int      acpi_pst_set_pstate(struct acpi_pst_softc *,
129                     const struct acpi_pstate *);
130 static const struct acpi_pstate *
131                 acpi_pst_get_pstate(struct acpi_pst_softc *);
132 static int      acpi_pst_alloc_resource(device_t, ACPI_OBJECT *, int,
133                     struct acpi_pst_res *);
134
135 static void     acpi_pst_check_csr_handler(netmsg_t);
136 static void     acpi_pst_check_pstates_handler(netmsg_t);
137 static void     acpi_pst_init_handler(netmsg_t);
138 static void     acpi_pst_set_pstate_handler(netmsg_t);
139 static void     acpi_pst_get_pstate_handler(netmsg_t);
140
141 static int      acpi_pst_sysctl_freqs(SYSCTL_HANDLER_ARGS);
142 static int      acpi_pst_sysctl_members(SYSCTL_HANDLER_ARGS);
143 static int      acpi_pst_sysctl_select(SYSCTL_HANDLER_ARGS);
144 static int      acpi_pst_sysctl_global(SYSCTL_HANDLER_ARGS);
145
146 static struct acpi_pst_domlist  acpi_pst_domains =
147         LIST_HEAD_INITIALIZER(acpi_pst_domains);
148 static int                      acpi_pst_domain_id;
149
150 static int                      acpi_pst_global_state;
151
152 static int                      acpi_npstates;
153 static struct acpi_pstate       *acpi_pstates;
154
155 static const struct acpi_pst_md *acpi_pst_md;
156
157 static device_method_t acpi_pst_methods[] = {
158         /* Device interface */
159         DEVMETHOD(device_probe,                 acpi_pst_probe),
160         DEVMETHOD(device_attach,                acpi_pst_attach),
161         DEVMETHOD(device_detach,                bus_generic_detach),
162         DEVMETHOD(device_shutdown,              bus_generic_shutdown),
163         DEVMETHOD(device_suspend,               bus_generic_suspend),
164         DEVMETHOD(device_resume,                bus_generic_resume),
165
166         /* Bus interface */
167         DEVMETHOD(bus_add_child,                bus_generic_add_child),
168         DEVMETHOD(bus_print_child,              bus_generic_print_child),
169         DEVMETHOD(bus_read_ivar,                bus_generic_read_ivar),
170         DEVMETHOD(bus_write_ivar,               bus_generic_write_ivar),
171         DEVMETHOD(bus_get_resource_list,        bus_generic_get_resource_list),
172         DEVMETHOD(bus_set_resource,             bus_generic_rl_set_resource),
173         DEVMETHOD(bus_get_resource,             bus_generic_rl_get_resource),
174         DEVMETHOD(bus_alloc_resource,           bus_generic_alloc_resource),
175         DEVMETHOD(bus_release_resource,         bus_generic_release_resource),
176         DEVMETHOD(bus_driver_added,             bus_generic_driver_added),
177         DEVMETHOD(bus_activate_resource,        bus_generic_activate_resource),
178         DEVMETHOD(bus_deactivate_resource,      bus_generic_deactivate_resource),
179         DEVMETHOD(bus_setup_intr,               bus_generic_setup_intr),
180         DEVMETHOD(bus_teardown_intr,            bus_generic_teardown_intr),
181
182         { 0, 0 }
183 };
184
185 static driver_t acpi_pst_driver = {
186         "cpu_pst",
187         acpi_pst_methods,
188         sizeof(struct acpi_pst_softc)
189 };
190
191 static devclass_t acpi_pst_devclass;
192 DRIVER_MODULE(cpu_pst, cpu, acpi_pst_driver, acpi_pst_devclass, 0, 0);
193 MODULE_DEPEND(cpu_pst, acpi, 1, 1, 1);
194
195 static __inline int
196 acpi_pst_freq2index(int freq)
197 {
198         int i;
199
200         for (i = 0; i < acpi_npstates; ++i) {
201                 if (acpi_pstates[i].st_freq == freq)
202                         return i;
203         }
204         return -1;
205 }
206
207 static int
208 acpi_pst_probe(device_t dev)
209 {
210         ACPI_BUFFER buf;
211         ACPI_HANDLE handle;
212         ACPI_STATUS status;
213         ACPI_OBJECT *obj;
214
215         if (acpi_disabled("cpu_pst") ||
216             acpi_get_type(dev) != ACPI_TYPE_PROCESSOR)
217                 return ENXIO;
218
219         if (acpi_pst_md == NULL)
220                 acpi_pst_md = acpi_pst_md_probe();
221
222         handle = acpi_get_handle(dev);
223
224         /*
225          * Check _PCT package
226          */
227         buf.Pointer = NULL;
228         buf.Length = ACPI_ALLOCATE_BUFFER;
229         status = AcpiEvaluateObject(handle, "_PCT", NULL, &buf);
230         if (ACPI_FAILURE(status)) {
231                 if (bootverbose) {
232                         device_printf(dev, "Can't get _PCT package - %s\n",
233                                       AcpiFormatException(status));
234                 }
235                 return ENXIO;
236         }
237
238         obj = (ACPI_OBJECT *)buf.Pointer;
239         if (!ACPI_PKG_VALID_EQ(obj, 2)) {
240                 device_printf(dev, "Invalid _PCT package\n");
241                 AcpiOsFree(obj);
242                 return ENXIO;
243         }
244         AcpiOsFree(obj);
245
246         /*
247          * Check _PSS package
248          */
249         buf.Pointer = NULL;
250         buf.Length = ACPI_ALLOCATE_BUFFER;
251         status = AcpiEvaluateObject(handle, "_PSS", NULL, &buf);
252         if (ACPI_FAILURE(status)) {
253                 device_printf(dev, "Can't get _PSS package - %s\n",
254                               AcpiFormatException(status));
255                 return ENXIO;
256         }
257
258         obj = (ACPI_OBJECT *)buf.Pointer;
259         if (!ACPI_PKG_VALID(obj, 1)) {
260                 device_printf(dev, "Invalid _PSS package\n");
261                 AcpiOsFree(obj);
262                 return ENXIO;
263         }
264         AcpiOsFree(obj);
265
266         device_set_desc(dev, "ACPI CPU P-State");
267         return 0;
268 }
269
270 static int
271 acpi_pst_attach(device_t dev)
272 {
273         struct acpi_pst_softc *sc = device_get_softc(dev), *pst;
274         struct acpi_pst_domain *dom = NULL;
275         ACPI_BUFFER buf;
276         ACPI_STATUS status;
277         ACPI_OBJECT *obj;
278         struct acpi_pstate *pstate, *p;
279         int i, npstate, error;
280
281         sc->pst_dev = dev;
282         sc->pst_parent = device_get_softc(device_get_parent(dev));
283         sc->pst_handle = acpi_get_handle(dev);
284         sc->pst_cpuid = acpi_get_magic(dev);
285
286         /*
287          * If there is a _PSD, then we create procossor domain
288          * accordingly.  If there is no _PSD, we just fake a
289          * default processor domain0.
290          */
291         buf.Pointer = NULL;
292         buf.Length = ACPI_ALLOCATE_BUFFER;
293         status = AcpiEvaluateObject(sc->pst_handle, "_PSD", NULL, &buf);
294         if (!ACPI_FAILURE(status)) {
295                 obj = (ACPI_OBJECT *)buf.Pointer;
296                 if (ACPI_PKG_VALID_EQ(obj, 1)) {
297                         dom = acpi_pst_domain_create(dev,
298                                 &obj->Package.Elements[0]);
299                         if (dom == NULL) {
300                                 AcpiOsFree(obj);
301                                 return ENXIO;
302                         }
303                 } else {
304                         device_printf(dev, "Invalid _PSD package\n");
305                         AcpiOsFree(obj);
306                         return ENXIO;
307                 }
308
309                 /* Free _PSD */
310                 AcpiOsFree(buf.Pointer);
311         } else {
312                 /*
313                  * Create a stub one processor domain for each processor
314                  */
315                 dom = acpi_pst_domain_alloc(acpi_pst_domain_id,
316                         ACPI_PSD_COORD_SWANY, 1);
317                 dom->pd_flags |= ACPI_PSTDOM_FLAG_STUB;
318
319                 ++acpi_pst_domain_id;
320         }
321
322         /* Make sure that adding us will not overflow our domain */
323         i = 0;
324         LIST_FOREACH(pst, &dom->pd_pstlist, pst_link)
325                 ++i;
326         if (i == dom->pd_nproc) {
327                 device_printf(dev, "Domain%u already contains %d P-States, "
328                               "invalid _PSD package\n",
329                               dom->pd_dom, dom->pd_nproc);
330                 return ENXIO;
331         }
332         KKASSERT(i < dom->pd_nproc);
333
334         /*
335          * Get control/status registers from _PCT
336          */
337         buf.Pointer = NULL;
338         buf.Length = ACPI_ALLOCATE_BUFFER;
339         status = AcpiEvaluateObject(sc->pst_handle, "_PCT", NULL, &buf);
340         if (ACPI_FAILURE(status)) {
341                 device_printf(dev, "Can't get _PCT package - %s\n",
342                               AcpiFormatException(status));
343                 return ENXIO;
344         }
345
346         obj = (ACPI_OBJECT *)buf.Pointer;
347         if (!ACPI_PKG_VALID_EQ(obj, 2)) {
348                 device_printf(dev, "Invalid _PCT package\n");
349                 AcpiOsFree(obj);
350                 return ENXIO;
351         }
352
353         /* Save and try allocating control register */
354         error = acpi_pst_alloc_resource(dev, obj, 0, &sc->pst_creg);
355         if (error) {
356                 AcpiOsFree(obj);
357                 return error;
358         }
359         if (bootverbose) {
360                 device_printf(dev, "control reg %d %jx\n",
361                               sc->pst_creg.pr_gas.SpaceId,
362                               (uintmax_t)sc->pst_creg.pr_gas.Address);
363         }
364
365         /* Save and try allocating status register */
366         error = acpi_pst_alloc_resource(dev, obj, 1, &sc->pst_sreg);
367         if (error) {
368                 AcpiOsFree(obj);
369                 return error;
370         }
371         if (bootverbose) {
372                 device_printf(dev, "status reg %d %jx\n",
373                               sc->pst_sreg.pr_gas.SpaceId,
374                               (uintmax_t)sc->pst_sreg.pr_gas.Address);
375         }
376
377         /* Free _PCT */
378         AcpiOsFree(obj);
379
380         /*
381          * Create P-State table according to _PSS
382          */
383         buf.Pointer = NULL;
384         buf.Length = ACPI_ALLOCATE_BUFFER;
385         status = AcpiEvaluateObject(sc->pst_handle, "_PSS", NULL, &buf);
386         if (ACPI_FAILURE(status)) {
387                 device_printf(dev, "Can't get _PSS package - %s\n",
388                               AcpiFormatException(status));
389                 return ENXIO;
390         }
391
392         obj = (ACPI_OBJECT *)buf.Pointer;
393         if (!ACPI_PKG_VALID(obj, 1)) {
394                 device_printf(dev, "Invalid _PSS package\n");
395                 AcpiOsFree(obj);
396                 return ENXIO;
397         }
398
399         /* Don't create too many P-States */
400         npstate = obj->Package.Count;
401         if (npstate > ACPI_NPSTATE_MAX) {
402                 device_printf(dev, "Too many P-States, %d->%d\n",
403                               npstate, ACPI_NPSTATE_MAX);
404                 npstate = ACPI_NPSTATE_MAX;
405         }
406
407         /*
408          * If we have already created P-State table,
409          * we must make sure that number of entries
410          * is consistent.
411          */
412         if (acpi_pstates != NULL && acpi_npstates != npstate) {
413                 device_printf(dev, "Inconsistent # of P-States "
414                               "cross Processor objects\n");
415                 AcpiOsFree(obj);
416                 return ENXIO;
417         }
418
419         /*
420          * Create a temporary P-State table
421          */
422         pstate = kmalloc(sizeof(*pstate) * npstate, M_TEMP, M_WAITOK);
423         for (i = 0, p = pstate; i < npstate; ++i, ++p) {
424                 ACPI_OBJECT *pkg;
425                 uint32_t *ptr[ACPI_PSS_PX_NENTRY] = {
426                         &p->st_freq, &p->st_power, &p->st_xsit_lat,
427                         &p->st_bm_lat, &p->st_cval, &p->st_sval
428                 };
429                 int j;
430
431                 pkg = &obj->Package.Elements[i];
432                 if (!ACPI_PKG_VALID(pkg, ACPI_PSS_PX_NENTRY)) {
433                         device_printf(dev, "Invalud _PSS P%d\n", i);
434                         AcpiOsFree(obj);
435                         kfree(pstate, M_TEMP);
436                         return ENXIO;
437                 }
438                 for (j = 0; j < ACPI_PSS_PX_NENTRY; ++j) {
439                         if (acpi_PkgInt32(pkg, j, ptr[j]) != 0) {
440                                 device_printf(dev, "Can't extract "
441                                               "_PSS P%d %dth entry\n", i, j);
442                                 AcpiOsFree(obj);
443                                 kfree(pstate, M_TEMP);
444                                 return ENXIO;
445                         }
446                 }
447         }
448
449         /* Free _PSS */
450         AcpiOsFree(obj);
451
452         if (acpi_pstates == NULL) {
453                 /*
454                  * If no P-State table is created yet,
455                  * save the temporary one we just created.
456                  */
457                 acpi_pstates = pstate;
458                 acpi_npstates = npstate;
459                 pstate = NULL;
460
461                 if (bootverbose) {
462                         for (i = 0; i < acpi_npstates; ++i) {
463                                 device_printf(dev,
464                                 "freq %u, pwr %u, xlat %u, blat %u, "
465                                 "cv %08x, sv %08x\n",
466                                 acpi_pstates[i].st_freq,
467                                 acpi_pstates[i].st_power,
468                                 acpi_pstates[i].st_xsit_lat,
469                                 acpi_pstates[i].st_bm_lat,
470                                 acpi_pstates[i].st_cval,
471                                 acpi_pstates[i].st_sval);
472                         }
473                 }
474         } else {
475                 /*
476                  * Make sure that P-State tables are same
477                  * for all processors.
478                  */
479                 if (memcmp(pstate, acpi_pstates,
480                            sizeof(*pstate) * npstate) != 0) {
481                         device_printf(dev, "Inconsistent _PSS "
482                                       "cross Processor objects\n");
483                         kfree(pstate, M_TEMP);
484                         return ENXIO;
485                 }
486                 kfree(pstate, M_TEMP);
487         }
488
489         /* By default, we start from P-State table's first entry */
490         sc->pst_sstart = 0;
491
492         /*
493          * Adjust the usable first entry of P-State table,
494          * if there is _PPC object.
495          */
496         buf.Pointer = NULL;
497         buf.Length = ACPI_ALLOCATE_BUFFER;
498         status = AcpiEvaluateObject(sc->pst_handle, "_PPC", NULL, &buf);
499         if (!ACPI_FAILURE(status)) {
500                 obj = (ACPI_OBJECT *)buf.Pointer;
501                 if (obj->Type == ACPI_TYPE_INTEGER) {
502                         if (obj->Integer.Value >= acpi_npstates) {
503                                 device_printf(dev, "Invalid _PPC value\n");
504                                 AcpiOsFree(obj);
505                                 return ENXIO;
506                         }
507                         sc->pst_sstart = obj->Integer.Value;
508                         if (bootverbose)
509                                 device_printf(dev, "_PPC %d\n", sc->pst_sstart);
510
511                         /* TODO: Install notifiy handler */
512                 } else {
513                         device_printf(dev, "Invalid _PPC object\n");
514                         AcpiOsFree(obj);
515                         return ENXIO;
516                 }
517
518                 /* Free _PPC */
519                 AcpiOsFree(obj);
520         }
521
522         sc->pst_state = sc->pst_sstart;
523
524         /* Link us with the domain */
525         sc->pst_domain = dom;
526         LIST_INSERT_HEAD(&dom->pd_pstlist, sc, pst_link);
527
528         if (device_get_unit(dev) == 0)
529                 AcpiOsExecute(OSL_NOTIFY_HANDLER, acpi_pst_postattach, NULL);
530
531         return 0;
532 }
533
534 static struct acpi_pst_domain *
535 acpi_pst_domain_create(device_t dev, ACPI_OBJECT *obj)
536 {
537         struct acpi_pst_domain *dom;
538         uint32_t val, domain, coord, nproc;
539
540         if (!ACPI_PKG_VALID_EQ(obj, 5)) {
541                 device_printf(dev, "Invalid _PSD package\n");
542                 return NULL;
543         }
544
545         /* NumberOfEntries */
546         if (acpi_PkgInt32(obj, 0, &val) != 0 || val != 5) {
547                 device_printf(dev, "Invalid _PSD NumberOfEntries\n");
548                 return NULL;
549         }
550
551         /* Revision */
552         if (acpi_PkgInt32(obj, 1, &val) != 0 || val != 0) {
553                 device_printf(dev, "Invalid _PSD Revision\n");
554                 return NULL;
555         }
556
557         if (acpi_PkgInt32(obj, 2, &domain) != 0 ||
558             acpi_PkgInt32(obj, 3, &coord) != 0 ||
559             acpi_PkgInt32(obj, 4, &nproc) != 0) {
560                 device_printf(dev, "Can't extract _PSD package\n");
561                 return NULL;
562         }
563
564         if (!ACPI_PSD_COORD_VALID(coord)) {
565                 device_printf(dev, "Invalid _PSD CoordType (%#x)\n", coord);
566                 return NULL;
567         }
568
569         if (nproc > MAXCPU) {
570                 /*
571                  * If NumProcessors is greater than MAXCPU
572                  * and domain's coordination is SWALL, then
573                  * we will never be able to start all CPUs
574                  * within this domain, and power state
575                  * transition will never be completed, so we
576                  * just bail out here.
577                  */
578                 if (coord == ACPI_PSD_COORD_SWALL) {
579                         device_printf(dev, "Unsupported _PSD NumProcessors "
580                                       "(%d)\n", nproc);
581                         return NULL;
582                 }
583         } else if (nproc == 0) {
584                 device_printf(dev, "_PSD NumProcessors are zero\n");
585                 return NULL;
586         }
587
588         dom = acpi_pst_domain_find(domain);
589         if (dom != NULL) {
590                 if (dom->pd_coord != coord || dom->pd_nproc != nproc) {
591                         device_printf(dev, "Inconsistent _PSD information "
592                                       "cross Processor objects\n");
593                         return NULL;
594                 }
595                 return dom;
596         }
597
598         dom = acpi_pst_domain_alloc(domain, coord, nproc);
599         if (bootverbose)
600                 device_printf(dev, "create domain%u\n", dom->pd_dom);
601
602         return dom;
603 }
604
605 static struct acpi_pst_domain *
606 acpi_pst_domain_find(uint32_t domain)
607 {
608         struct acpi_pst_domain *dom;
609
610         LIST_FOREACH(dom, &acpi_pst_domains, pd_link) {
611                 if (dom->pd_flags & ACPI_PSTDOM_FLAG_STUB)
612                         continue;
613                 if (dom->pd_dom == domain)
614                         return dom;
615         }
616         return NULL;
617 }
618
619 static struct acpi_pst_domain *
620 acpi_pst_domain_alloc(uint32_t domain, uint32_t coord, uint32_t nproc)
621 {
622         struct acpi_pst_domain *dom;
623
624         dom = kmalloc(sizeof(*dom), M_DEVBUF, M_WAITOK | M_ZERO);
625         dom->pd_dom = domain;
626         dom->pd_coord = coord;
627         dom->pd_nproc = nproc;
628         dom->pd_state = 0; /* XXX */
629         dom->pd_sstart = 0; /* XXX */
630         LIST_INIT(&dom->pd_pstlist);
631
632         LIST_INSERT_HEAD(&acpi_pst_domains, dom, pd_link);
633
634         return dom;
635 }
636
637 static int
638 acpi_pst_domain_set_pstate(struct acpi_pst_domain *dom, int i)
639 {
640         const struct acpi_pstate *pstate;
641         struct acpi_pst_softc *sc;
642         int done, error;
643
644         KKASSERT(i >= 0 && i < acpi_npstates);
645         pstate = &acpi_pstates[i];
646
647         done = 0;
648         LIST_FOREACH(sc, &dom->pd_pstlist, pst_link) {
649                 if (!done) {
650                         error = acpi_pst_set_pstate(sc, pstate);
651                         if (error) {
652                                 device_printf(sc->pst_dev, "can't set "
653                                               "freq %d\n", pstate->st_freq);
654                                 /* XXX error cleanup? */
655                         }
656                         if (dom->pd_coord == ACPI_PSD_COORD_SWANY)
657                                 done = 1;
658                 }
659                 sc->pst_state = i;
660         }
661         dom->pd_state = i;
662
663         return 0;
664 }
665
666 static int
667 acpi_pst_global_set_pstate(int i)
668 {
669         struct acpi_pst_domain *dom;
670
671         LIST_FOREACH(dom, &acpi_pst_domains, pd_link) {
672                 /* Skip dead domain */
673                 if (dom->pd_flags & ACPI_PSTDOM_FLAG_DEAD)
674                         continue;
675                 acpi_pst_domain_set_pstate(dom, i);
676         }
677         acpi_pst_global_state = i;
678
679         return 0;
680 }
681
682 static void
683 acpi_pst_postattach(void *arg __unused)
684 {
685         struct acpi_pst_domain *dom;
686         struct acpi_cpux_softc *cpux;
687         device_t *devices;
688         int i, ndevices, error, has_domain, sstate;
689
690         devices = NULL;
691         ndevices = 0;
692         error = devclass_get_devices(acpi_pst_devclass, &devices, &ndevices);
693         if (error)
694                 return;
695
696         if (ndevices == 0)
697                 return;
698
699         cpux = NULL;
700         for (i = 0; i < ndevices; ++i) {
701                 cpux = device_get_softc(device_get_parent(devices[i]));
702                 if (cpux->glob_sysctl_tree != NULL)
703                         break;
704         }
705         kfree(devices, M_TEMP);
706         KKASSERT(cpux != NULL);
707
708         if (acpi_pst_md == NULL)
709                 kprintf("ACPI: no P-State CPU driver\n");
710
711         sstate = 0x7fffffff;
712         has_domain = 0;
713         LIST_FOREACH(dom, &acpi_pst_domains, pd_link) {
714                 struct acpi_pst_softc *sc;
715                 char buf[32];
716
717                 /*
718                  * Make sure that all processors belonging to this
719                  * domain are located.
720                  */
721                 i = 0;
722                 LIST_FOREACH(sc, &dom->pd_pstlist, pst_link)
723                         ++i;
724                 if (i != dom->pd_nproc) {
725                         KKASSERT(i < dom->pd_nproc);
726
727                         kprintf("ACPI: domain%u misses processors, "
728                                 "should be %d, got %d\n", dom->pd_dom,
729                                 dom->pd_nproc, i);
730                         if (dom->pd_coord == ACPI_PSD_COORD_SWALL) {
731                                 /*
732                                  * If this domain's coordination is
733                                  * SWALL and we don't see all of the
734                                  * member CPUs of this domain, then
735                                  * the P-State transition will never
736                                  * be completed, so just leave this
737                                  * domain out.
738                                  */
739                                 dom->pd_flags |= ACPI_PSTDOM_FLAG_DEAD;
740                                 continue;
741                         }
742                         dom->pd_nproc = i;
743                 }
744
745                 /*
746                  * Validate P-State configurations for this domain
747                  */
748                 LIST_FOREACH(sc, &dom->pd_pstlist, pst_link) {
749                         error = acpi_pst_check_csr(sc);
750                         if (error)
751                                 break;
752
753                         error = acpi_pst_check_pstates(sc);
754                         if (error)
755                                 break;
756                 }
757                 if (sc != NULL) {
758                         kprintf("ACPI: domain%u P-State configuration "
759                                 "check failed\n", dom->pd_dom);
760                         dom->pd_flags |= ACPI_PSTDOM_FLAG_DEAD;
761                         continue;
762                 }
763
764                 /*
765                  * Do necssary P-State initialization
766                  */
767                 LIST_FOREACH(sc, &dom->pd_pstlist, pst_link) {
768                         error = acpi_pst_init(sc);
769                         if (error)
770                                 break;
771                 }
772                 if (sc != NULL) {
773                         kprintf("ACPI: domain%u P-State initialization "
774                                 "check failed\n", dom->pd_dom);
775                         dom->pd_flags |= ACPI_PSTDOM_FLAG_DEAD;
776                         continue;
777                 }
778
779                 has_domain = 1;
780
781                 ksnprintf(buf, sizeof(buf), "px_dom%u", dom->pd_dom);
782
783                 sysctl_ctx_init(&dom->pd_sysctl_ctx);
784                 dom->pd_sysctl_tree =
785                 SYSCTL_ADD_NODE(&dom->pd_sysctl_ctx,
786                         SYSCTL_CHILDREN(cpux->glob_sysctl_tree),
787                         OID_AUTO, buf, CTLFLAG_RD, 0,
788                         "P-State domain");
789                 if (dom->pd_sysctl_tree == NULL) {
790                         kprintf("ACPI: Can't create sysctl tree for domain%u",
791                                 dom->pd_dom);
792                         continue;
793                 }
794
795                 SYSCTL_ADD_PROC(&dom->pd_sysctl_ctx,
796                                 SYSCTL_CHILDREN(dom->pd_sysctl_tree),
797                                 OID_AUTO, "available",
798                                 CTLTYPE_STRING | CTLFLAG_RD,
799                                 dom, 0, acpi_pst_sysctl_freqs, "A",
800                                 "available frequencies");
801
802                 SYSCTL_ADD_PROC(&dom->pd_sysctl_ctx,
803                                 SYSCTL_CHILDREN(dom->pd_sysctl_tree),
804                                 OID_AUTO, "members",
805                                 CTLTYPE_STRING | CTLFLAG_RD,
806                                 dom, 0, acpi_pst_sysctl_members, "A",
807                                 "member cpus");
808
809                 if (acpi_pst_md != NULL &&
810                     acpi_pst_md->pmd_set_pstate != NULL) {
811                         SYSCTL_ADD_PROC(&dom->pd_sysctl_ctx,
812                                         SYSCTL_CHILDREN(dom->pd_sysctl_tree),
813                                         OID_AUTO, "select",
814                                         CTLTYPE_UINT | CTLFLAG_RW,
815                                         dom, 0, acpi_pst_sysctl_select,
816                                         "IU", "select freq");
817                 }
818
819                 if (dom->pd_state < sstate)
820                         sstate = dom->pd_state;
821         }
822
823         if (has_domain && acpi_pst_md != NULL &&
824             acpi_pst_md->pmd_set_pstate != NULL) {
825                 SYSCTL_ADD_PROC(&cpux->glob_sysctl_ctx,
826                                 SYSCTL_CHILDREN(cpux->glob_sysctl_tree),
827                                 OID_AUTO, "px_global",
828                                 CTLTYPE_UINT | CTLFLAG_RW,
829                                 NULL, 0, acpi_pst_sysctl_global,
830                                 "IU", "select freq for all domains");
831
832                 acpi_pst_global_set_pstate(sstate);
833         }
834 }
835
836 static int
837 acpi_pst_sysctl_freqs(SYSCTL_HANDLER_ARGS)
838 {
839         struct acpi_pst_domain *dom = arg1;
840         int i, error;
841
842         error = 0;
843         for (i = 0; i < acpi_npstates; ++i) {
844                 if (error == 0 && i)
845                         error = SYSCTL_OUT(req, " ", 1);
846                 if (error == 0) {
847                         const char *pat;
848                         char buf[32];
849
850                         if (i < dom->pd_sstart)
851                                 pat = "(%u)";
852                         else
853                                 pat = "%u";
854
855                         ksnprintf(buf, sizeof(buf), pat,
856                                   acpi_pstates[i].st_freq);
857                         error = SYSCTL_OUT(req, buf, strlen(buf));
858                 }
859         }
860         return error;
861 }
862
863 static int
864 acpi_pst_sysctl_members(SYSCTL_HANDLER_ARGS)
865 {
866         struct acpi_pst_domain *dom = arg1;
867         struct acpi_pst_softc *sc;
868         int loop, error;
869
870         loop = error = 0;
871         LIST_FOREACH(sc, &dom->pd_pstlist, pst_link) {
872                 char buf[32];
873
874                 if (error == 0 && loop)
875                         error = SYSCTL_OUT(req, " ", 1);
876                 if (error == 0) {
877                         ksnprintf(buf, sizeof(buf), "cpu%d", sc->pst_cpuid);
878                         error = SYSCTL_OUT(req, buf, strlen(buf));
879                 }
880
881                 if (error == 0 && acpi_pst_md && acpi_pst_md->pmd_get_pstate) {
882                         const struct acpi_pstate *pstate;
883                         const char *str;
884
885                         pstate = acpi_pst_get_pstate(sc);
886                         if (pstate == NULL) {
887                                 str = "(*)";
888                         } else {
889                                 ksnprintf(buf, sizeof(buf), "(%d)",
890                                           pstate->st_freq);
891                                 str = buf;
892                         }
893                         error = SYSCTL_OUT(req, str, strlen(str));
894                 }
895                 ++loop;
896         }
897         return error;
898 }
899
900 static int
901 acpi_pst_sysctl_select(SYSCTL_HANDLER_ARGS)
902 {
903         struct acpi_pst_domain *dom = arg1;
904         int error, i, freq;
905
906         KKASSERT(dom->pd_state >= 0 && dom->pd_state < acpi_npstates);
907
908         freq = acpi_pstates[dom->pd_state].st_freq;
909
910         error = sysctl_handle_int(oidp, &freq, 0, req);
911         if (error || req->newptr == NULL)
912                 return error;
913
914         i = acpi_pst_freq2index(freq);
915         if (i < 0)
916                 return EINVAL;
917
918         acpi_pst_domain_set_pstate(dom, i);
919         return 0;
920 }
921
922 static int
923 acpi_pst_sysctl_global(SYSCTL_HANDLER_ARGS)
924 {
925         int error, i, freq;
926
927         KKASSERT(acpi_pst_global_state >= 0 &&
928                  acpi_pst_global_state < acpi_npstates);
929
930         freq = acpi_pstates[acpi_pst_global_state].st_freq;
931
932         error = sysctl_handle_int(oidp, &freq, 0, req);
933         if (error || req->newptr == NULL)
934                 return error;
935
936         i = acpi_pst_freq2index(freq);
937         if (i < 0)
938                 return EINVAL;
939
940         acpi_pst_global_set_pstate(i);
941
942         return 0;
943 }
944
945 static void
946 acpi_pst_check_csr_handler(netmsg_t msg)
947 {
948         struct netmsg_acpi_pst *rmsg = (struct netmsg_acpi_pst *)msg;
949         int error;
950
951         error = acpi_pst_md->pmd_check_csr(rmsg->ctrl, rmsg->status);
952         lwkt_replymsg(&rmsg->base.lmsg, error);
953 }
954
955 static int
956 acpi_pst_check_csr(struct acpi_pst_softc *sc)
957 {
958         struct netmsg_acpi_pst msg;
959
960         if (acpi_pst_md == NULL)
961                 return 0;
962
963         netmsg_init(&msg.base, NULL, &curthread->td_msgport,
964                     MSGF_PRIORITY, acpi_pst_check_csr_handler);
965         msg.ctrl = &sc->pst_creg;
966         msg.status = &sc->pst_sreg;
967
968         return lwkt_domsg(cpu_portfn(sc->pst_cpuid), &msg.base.lmsg, 0);
969 }
970
971 static void
972 acpi_pst_check_pstates_handler(netmsg_t msg)
973 {
974         int error;
975
976         error = acpi_pst_md->pmd_check_pstates(acpi_pstates, acpi_npstates);
977         lwkt_replymsg(&msg->lmsg, error);
978 }
979
980 static int
981 acpi_pst_check_pstates(struct acpi_pst_softc *sc)
982 {
983         struct netmsg_base msg;
984
985         if (acpi_pst_md == NULL)
986                 return 0;
987
988         netmsg_init(&msg, NULL, &curthread->td_msgport,
989                     MSGF_PRIORITY, acpi_pst_check_pstates_handler);
990
991         return lwkt_domsg(cpu_portfn(sc->pst_cpuid), &msg.lmsg, 0);
992 }
993
994 static void
995 acpi_pst_init_handler(netmsg_t msg)
996 {
997         struct netmsg_acpi_pst *rmsg = (struct netmsg_acpi_pst *)msg;
998         int error;
999
1000         error = acpi_pst_md->pmd_init(rmsg->ctrl, rmsg->status);
1001         lwkt_replymsg(&rmsg->base.lmsg, error);
1002 }
1003
1004 static int
1005 acpi_pst_init(struct acpi_pst_softc *sc)
1006 {
1007         struct netmsg_acpi_pst msg;
1008
1009         if (acpi_pst_md == NULL)
1010                 return 0;
1011
1012         netmsg_init(&msg.base, NULL, &curthread->td_msgport,
1013                     MSGF_PRIORITY, acpi_pst_init_handler);
1014         msg.ctrl = &sc->pst_creg;
1015         msg.status = &sc->pst_sreg;
1016
1017         return lwkt_domsg(cpu_portfn(sc->pst_cpuid), &msg.base.lmsg, 0);
1018 }
1019
1020 static void
1021 acpi_pst_set_pstate_handler(netmsg_t msg)
1022 {
1023         struct netmsg_acpi_pst *rmsg = (struct netmsg_acpi_pst *)msg;
1024         int error;
1025
1026         error = acpi_pst_md->pmd_set_pstate(rmsg->ctrl, rmsg->status,
1027                                             rmsg->base.lmsg.u.ms_resultp);
1028         lwkt_replymsg(&rmsg->base.lmsg, error);
1029 }
1030
1031 static int
1032 acpi_pst_set_pstate(struct acpi_pst_softc *sc, const struct acpi_pstate *pstate)
1033 {
1034         struct netmsg_acpi_pst msg;
1035
1036         KKASSERT(acpi_pst_md != NULL);
1037
1038         netmsg_init(&msg.base, NULL, &curthread->td_msgport,
1039                     MSGF_PRIORITY, acpi_pst_set_pstate_handler);
1040         msg.base.lmsg.u.ms_resultp = __DECONST(void *, pstate);
1041         msg.ctrl = &sc->pst_creg;
1042         msg.status = &sc->pst_sreg;
1043
1044         return lwkt_domsg(cpu_portfn(sc->pst_cpuid), &msg.base.lmsg, 0);
1045 }
1046
1047 static void
1048 acpi_pst_get_pstate_handler(netmsg_t msg)
1049 {
1050         struct netmsg_acpi_pst *rmsg = (struct netmsg_acpi_pst *)msg;
1051         const struct acpi_pstate *pstate;
1052
1053         pstate = acpi_pst_md->pmd_get_pstate(rmsg->status, acpi_pstates,
1054                                              acpi_npstates);
1055         rmsg->base.lmsg.u.ms_resultp = __DECONST(void *, pstate);
1056         lwkt_replymsg(&rmsg->base.lmsg, 0);
1057 }
1058
1059 static const struct acpi_pstate *
1060 acpi_pst_get_pstate(struct acpi_pst_softc *sc)
1061 {
1062         struct netmsg_acpi_pst msg;
1063
1064         if (acpi_pst_md == NULL)
1065                 return 0;
1066
1067         netmsg_init(&msg.base, NULL, &curthread->td_msgport,
1068                     MSGF_PRIORITY, acpi_pst_get_pstate_handler);
1069         msg.status = &sc->pst_sreg;
1070
1071         lwkt_domsg(cpu_portfn(sc->pst_cpuid), &msg.base.lmsg, 0);
1072         return msg.base.lmsg.u.ms_resultp;
1073 }
1074
1075 static int
1076 acpi_pst_alloc_resource(device_t dev, ACPI_OBJECT *obj, int idx,
1077                         struct acpi_pst_res *res)
1078 {
1079         struct acpi_pst_softc *sc = device_get_softc(dev);
1080         int error, type;
1081
1082         /* Save GAS */
1083         error = acpi_PkgRawGas(obj, idx, &res->pr_gas);
1084         if (error)
1085                 return error;
1086
1087         /* Allocate resource, if possible */
1088         res->pr_rid = sc->pst_parent->cpux_next_rid;
1089         acpi_bus_alloc_gas(dev, &type, &res->pr_rid, &res->pr_gas, &res->pr_res, 0);
1090         if (res->pr_res != NULL) {
1091                 sc->pst_parent->cpux_next_rid++;
1092                 res->pr_bt = rman_get_bustag(res->pr_res);
1093                 res->pr_bh = rman_get_bushandle(res->pr_res);
1094         } else {
1095                 res->pr_rid = 0;
1096         }
1097         return 0;
1098 }