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