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