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