]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/acpica/acpi_cmbat.c
acpi: Ensure that adjacent memory affinity table entries are coalesced
[FreeBSD/FreeBSD.git] / sys / dev / acpica / acpi_cmbat.c
1 /*-
2  * Copyright (c) 2005 Nate Lawson
3  * Copyright (c) 2000 Munehiro Matsuda
4  * Copyright (c) 2000 Takanori Watanabe
5  * Copyright (c) 2000 Mitsuru IWASAKI <iwasaki@FreeBSD.org>
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
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 the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32
33 #include "opt_acpi.h"
34 #include <sys/param.h>
35 #include <sys/kernel.h>
36 #include <sys/module.h>
37 #include <sys/bus.h>
38 #include <sys/ioccom.h>
39
40 #include <machine/bus.h>
41 #include <sys/rman.h>
42 #include <sys/malloc.h>
43
44 #include <contrib/dev/acpica/include/acpi.h>
45
46 #include <dev/acpica/acpivar.h>
47 #include <dev/acpica/acpiio.h>
48
49 static MALLOC_DEFINE(M_ACPICMBAT, "acpicmbat",
50     "ACPI control method battery data");
51
52 /* Number of times to retry initialization before giving up. */
53 #define ACPI_CMBAT_RETRY_MAX    6
54
55 /* Check the battery once a minute. */
56 #define CMBAT_POLLRATE          (60 * hz)
57
58 /* Hooks for the ACPI CA debugging infrastructure */
59 #define _COMPONENT      ACPI_BATTERY
60 ACPI_MODULE_NAME("BATTERY")
61
62 #define ACPI_BATTERY_BST_CHANGE 0x80
63 #define ACPI_BATTERY_BIF_CHANGE 0x81
64 #define ACPI_BATTERY_BIX_CHANGE ACPI_BATTERY_BIF_CHANGE
65
66 struct acpi_cmbat_softc {
67     device_t        dev;
68     int             flags;
69
70     struct acpi_bix bix;
71     struct acpi_bst bst;
72     struct timespec bst_lastupdated;
73 };
74
75 ACPI_SERIAL_DECL(cmbat, "ACPI cmbat");
76
77 static int              acpi_cmbat_probe(device_t dev);
78 static int              acpi_cmbat_attach(device_t dev);
79 static int              acpi_cmbat_detach(device_t dev);
80 static int              acpi_cmbat_resume(device_t dev);
81 static void             acpi_cmbat_notify_handler(ACPI_HANDLE h, UINT32 notify,
82                             void *context);
83 static int              acpi_cmbat_info_expired(struct timespec *lastupdated);
84 static void             acpi_cmbat_info_updated(struct timespec *lastupdated);
85 static void             acpi_cmbat_get_bst(void *arg);
86 static void             acpi_cmbat_get_bix_task(void *arg);
87 static void             acpi_cmbat_get_bix(void *arg);
88 static int              acpi_cmbat_bst(device_t, struct acpi_bst *);
89 static int              acpi_cmbat_bix(device_t, void *, size_t);
90 static void             acpi_cmbat_init_battery(void *arg);
91
92 static device_method_t acpi_cmbat_methods[] = {
93     /* Device interface */
94     DEVMETHOD(device_probe,     acpi_cmbat_probe),
95     DEVMETHOD(device_attach,    acpi_cmbat_attach),
96     DEVMETHOD(device_detach,    acpi_cmbat_detach),
97     DEVMETHOD(device_resume,    acpi_cmbat_resume),
98
99     /* ACPI battery interface */
100     DEVMETHOD(acpi_batt_get_info, acpi_cmbat_bix),
101     DEVMETHOD(acpi_batt_get_status, acpi_cmbat_bst),
102
103     DEVMETHOD_END
104 };
105
106 static driver_t acpi_cmbat_driver = {
107     "battery",
108     acpi_cmbat_methods,
109     sizeof(struct acpi_cmbat_softc),
110 };
111
112 static devclass_t acpi_cmbat_devclass;
113 DRIVER_MODULE(acpi_cmbat, acpi, acpi_cmbat_driver, acpi_cmbat_devclass, 0, 0);
114 MODULE_DEPEND(acpi_cmbat, acpi, 1, 1, 1);
115
116 static int
117 acpi_cmbat_probe(device_t dev)
118 {
119     static char *cmbat_ids[] = { "PNP0C0A", NULL };
120     int rv;
121     
122     if (acpi_disabled("cmbat"))
123         return (ENXIO);
124     rv = ACPI_ID_PROBE(device_get_parent(dev), dev, cmbat_ids, NULL);
125     if (rv <= 0)
126         device_set_desc(dev, "ACPI Control Method Battery");
127     return (rv);
128 }
129
130 static int
131 acpi_cmbat_attach(device_t dev)
132 {
133     int         error;
134     ACPI_HANDLE handle;
135     struct acpi_cmbat_softc *sc;
136
137     sc = device_get_softc(dev);
138     handle = acpi_get_handle(dev);
139     sc->dev = dev;
140
141     timespecclear(&sc->bst_lastupdated);
142
143     error = acpi_battery_register(dev);
144     if (error != 0) {
145         device_printf(dev, "registering battery failed\n");
146         return (error);
147     }
148
149     /*
150      * Install a system notify handler in addition to the device notify.
151      * Toshiba notebook uses this alternate notify for its battery.
152      */
153     AcpiInstallNotifyHandler(handle, ACPI_ALL_NOTIFY,
154         acpi_cmbat_notify_handler, dev);
155
156     AcpiOsExecute(OSL_NOTIFY_HANDLER, acpi_cmbat_init_battery, dev);
157
158     return (0);
159 }
160
161 static int
162 acpi_cmbat_detach(device_t dev)
163 {
164     ACPI_HANDLE handle;
165
166     handle = acpi_get_handle(dev);
167     AcpiRemoveNotifyHandler(handle, ACPI_ALL_NOTIFY, acpi_cmbat_notify_handler);
168     acpi_battery_remove(dev);
169
170     /*
171      * Force any pending notification handler calls to complete by
172      * requesting cmbat serialisation while freeing and clearing the
173      * softc pointer:
174      */
175     ACPI_SERIAL_BEGIN(cmbat);
176     device_set_softc(dev, NULL);
177     ACPI_SERIAL_END(cmbat);
178
179     return (0);
180 }
181
182 static int
183 acpi_cmbat_resume(device_t dev)
184 {
185
186     AcpiOsExecute(OSL_NOTIFY_HANDLER, acpi_cmbat_init_battery, dev);
187     return (0);
188 }
189
190 static void
191 acpi_cmbat_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context)
192 {
193     struct acpi_cmbat_softc *sc;
194     device_t dev;
195
196     dev = (device_t)context;
197     sc = device_get_softc(dev);
198
199     switch (notify) {
200     case ACPI_NOTIFY_DEVICE_CHECK:
201     case ACPI_BATTERY_BST_CHANGE:
202         /*
203          * Clear the last updated time.  The next call to retrieve the
204          * battery status will get the new value for us.
205          */
206         timespecclear(&sc->bst_lastupdated);
207         break;
208     case ACPI_NOTIFY_BUS_CHECK:
209     case ACPI_BATTERY_BIX_CHANGE:
210         /*
211          * Queue a callback to get the current battery info from thread
212          * context.  It's not safe to block in a notify handler.
213          */
214         AcpiOsExecute(OSL_NOTIFY_HANDLER, acpi_cmbat_get_bix_task, dev);
215         break;
216     }
217
218     acpi_UserNotify("CMBAT", h, notify);
219 }
220
221 static int
222 acpi_cmbat_info_expired(struct timespec *lastupdated)
223 {
224     struct timespec     curtime;
225
226     ACPI_SERIAL_ASSERT(cmbat);
227
228     if (lastupdated == NULL)
229         return (TRUE);
230     if (!timespecisset(lastupdated))
231         return (TRUE);
232
233     getnanotime(&curtime);
234     timespecsub(&curtime, lastupdated, &curtime);
235     return (curtime.tv_sec < 0 ||
236             curtime.tv_sec > acpi_battery_get_info_expire());
237 }
238
239 static void
240 acpi_cmbat_info_updated(struct timespec *lastupdated)
241 {
242
243     ACPI_SERIAL_ASSERT(cmbat);
244
245     if (lastupdated != NULL)
246         getnanotime(lastupdated);
247 }
248
249 static void
250 acpi_cmbat_get_bst(void *arg)
251 {
252     struct acpi_cmbat_softc *sc;
253     ACPI_STATUS as;
254     ACPI_OBJECT *res;
255     ACPI_HANDLE h;
256     ACPI_BUFFER bst_buffer;
257     device_t dev;
258
259     ACPI_SERIAL_ASSERT(cmbat);
260
261     dev = arg;
262     sc = device_get_softc(dev);
263     h = acpi_get_handle(dev);
264     bst_buffer.Pointer = NULL;
265     bst_buffer.Length = ACPI_ALLOCATE_BUFFER;
266
267     if (!acpi_cmbat_info_expired(&sc->bst_lastupdated))
268         goto end;
269
270     as = AcpiEvaluateObject(h, "_BST", NULL, &bst_buffer);
271     if (ACPI_FAILURE(as)) {
272         ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
273             "error fetching current battery status -- %s\n",
274             AcpiFormatException(as));
275         goto end;
276     }
277
278     res = (ACPI_OBJECT *)bst_buffer.Pointer;
279     if (!ACPI_PKG_VALID(res, 4)) {
280         ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
281             "battery status corrupted\n");
282         goto end;
283     }
284
285     if (acpi_PkgInt32(res, 0, &sc->bst.state) != 0)
286         goto end;
287     if (acpi_PkgInt32(res, 1, &sc->bst.rate) != 0)
288         goto end;
289     if (acpi_PkgInt32(res, 2, &sc->bst.cap) != 0)
290         goto end;
291     if (acpi_PkgInt32(res, 3, &sc->bst.volt) != 0)
292         goto end;
293     acpi_cmbat_info_updated(&sc->bst_lastupdated);
294
295     /* Clear out undefined/extended bits that might be set by hardware. */
296     sc->bst.state &= ACPI_BATT_STAT_BST_MASK;
297     if ((sc->bst.state & ACPI_BATT_STAT_INVALID) == ACPI_BATT_STAT_INVALID)
298         ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
299             "battery reports simultaneous charging and discharging\n");
300
301     /* XXX If all batteries are critical, perhaps we should suspend. */
302     if (sc->bst.state & ACPI_BATT_STAT_CRITICAL) {
303         if ((sc->flags & ACPI_BATT_STAT_CRITICAL) == 0) {
304             sc->flags |= ACPI_BATT_STAT_CRITICAL;
305             device_printf(dev, "critically low charge!\n");
306         }
307     } else
308         sc->flags &= ~ACPI_BATT_STAT_CRITICAL;
309
310 end:
311     AcpiOsFree(bst_buffer.Pointer);
312 }
313
314 /* XXX There should be a cleaner way to do this locking. */
315 static void
316 acpi_cmbat_get_bix_task(void *arg)
317 {
318
319     ACPI_SERIAL_BEGIN(cmbat);
320     acpi_cmbat_get_bix(arg);
321     ACPI_SERIAL_END(cmbat);
322 }
323
324 static void
325 acpi_cmbat_get_bix(void *arg)
326 {
327     struct acpi_cmbat_softc *sc;
328     ACPI_STATUS as;
329     ACPI_OBJECT *res;
330     ACPI_HANDLE h;
331     ACPI_BUFFER bix_buffer;
332     device_t dev;
333     int i, n;
334     const struct {
335             enum { _BIX, _BIF } type;
336             char *name;
337     } bobjs[] = {
338             { _BIX, "_BIX"},
339             { _BIF, "_BIF"},
340     };
341
342     ACPI_SERIAL_ASSERT(cmbat);
343
344     dev = arg;
345     sc = device_get_softc(dev);
346     h = acpi_get_handle(dev);
347     bix_buffer.Pointer = NULL;
348     bix_buffer.Length = ACPI_ALLOCATE_BUFFER;
349
350     for (n = 0; n < sizeof(bobjs); n++) {
351         as = AcpiEvaluateObject(h, bobjs[n].name, NULL, &bix_buffer);
352         if (!ACPI_FAILURE(as)) {
353             res = (ACPI_OBJECT *)bix_buffer.Pointer;
354             break;
355         }
356         AcpiOsFree(bix_buffer.Pointer);
357         bix_buffer.Pointer = NULL;
358         bix_buffer.Length = ACPI_ALLOCATE_BUFFER;
359     }
360     /* Both _BIF and _BIX were not found. */
361     if (n == sizeof(bobjs)) {
362         ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
363             "error fetching current battery info -- %s\n",
364             AcpiFormatException(as));
365         goto end;
366     }
367
368     /*
369      * ACPI _BIX and _BIF revision mismatch check:
370      *
371      * 1. _BIF has no revision field.  The number of fields must be 13.
372      *
373      * 2. _BIX has a revision field.  As of ACPI 6.3 it must be "0" or
374      *    "1".  The number of fields will be checked---20 and 21,
375      *    respectively.
376      *
377      *    If the revision number is grater than "1" and the number of
378      *    fields is grater than 21, it will be treated as compatible with
379      *    ACPI 6.0 _BIX.  If not, it will be ignored.
380      */
381     i = 0;
382     switch (bobjs[n].type) {
383     case _BIX:
384         if (acpi_PkgInt16(res, i++, &sc->bix.rev) != 0) {
385             ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
386                 "_BIX revision error\n");
387             goto end;
388         }
389 #define ACPI_BIX_REV_MISMATCH_ERR(x, r) do {                    \
390         ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),     \
391             "_BIX revision mismatch (%u != %u)\n", x, r);       \
392         goto end;                                               \
393         } while (0)
394
395         if (ACPI_PKG_VALID_EQ(res, 21)) {       /* ACPI 6.0 _BIX */
396             /*
397              * Some models have rev.0 _BIX with 21 members.
398              * In that case, treat the first 20 members as rev.0 _BIX.
399              */
400             if (sc->bix.rev != ACPI_BIX_REV_0 &&
401                 sc->bix.rev != ACPI_BIX_REV_1)
402                 ACPI_BIX_REV_MISMATCH_ERR(sc->bix.rev, ACPI_BIX_REV_1);
403         } else if (ACPI_PKG_VALID_EQ(res, 20)) {/* ACPI 4.0 _BIX */
404             if (sc->bix.rev != ACPI_BIX_REV_0)
405                 ACPI_BIX_REV_MISMATCH_ERR(sc->bix.rev, ACPI_BIX_REV_0);
406         } else if (ACPI_PKG_VALID(res, 22)) {
407             /* _BIX with 22 or more members. */
408             if (ACPI_BIX_REV_MIN_CHECK(sc->bix.rev, ACPI_BIX_REV_1 + 1)) {
409                 /*
410                  * Unknown revision number.
411                  * Assume 21 members are compatible with 6.0 _BIX.
412                  */
413                 ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
414                     "Unknown _BIX revision(%u). "
415                     "Assuming compatible with revision %u.\n",
416                     sc->bix.rev, ACPI_BIX_REV_1);
417             } else {
418                 /*
419                  * Known revision number.  Ignore the extra members.
420                  */
421                 ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
422                     "Extra objects found in _BIX were ignored.\n");
423             }
424         } else {
425                 /* Invalid _BIX.  Ignore it. */
426                 ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
427                     "Invalid _BIX found (rev=%u, count=%u).  Ignored.\n",
428                     sc->bix.rev, res->Package.Count);
429                 goto end;
430         }
431         break;
432 #undef  ACPI_BIX_REV_MISMATCH_ERR
433     case _BIF:
434         if (ACPI_PKG_VALID_EQ(res, 13)) /* _BIF */
435             sc->bix.rev = ACPI_BIX_REV_BIF;
436         else {
437                 ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
438                     "Invalid _BIF found (count=%u).  Ignored.\n",
439                     res->Package.Count);
440                 goto end;
441         }
442         break;
443     }
444
445     ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
446         "rev = %04x\n", sc->bix.rev);
447 #define BIX_GETU32(NAME)        do {                    \
448     ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev), \
449         #NAME " = %u\n", sc->bix.NAME);                 \
450     if (acpi_PkgInt32(res, i++, &sc->bix.NAME) != 0)    \
451             goto end;                                   \
452     } while (0)
453
454     BIX_GETU32(units);
455     BIX_GETU32(dcap);
456     BIX_GETU32(lfcap);
457     BIX_GETU32(btech);
458     BIX_GETU32(dvol);
459     BIX_GETU32(wcap);
460     BIX_GETU32(lcap);
461     if (ACPI_BIX_REV_MIN_CHECK(sc->bix.rev, ACPI_BIX_REV_0)) {
462             BIX_GETU32(cycles);
463             BIX_GETU32(accuracy);
464             BIX_GETU32(stmax);
465             BIX_GETU32(stmin);
466             BIX_GETU32(aimax);
467             BIX_GETU32(aimin);
468     }
469     BIX_GETU32(gra1);
470     BIX_GETU32(gra2);
471     if (acpi_PkgStr(res, i++, sc->bix.model, ACPI_CMBAT_MAXSTRLEN) != 0)
472             goto end;
473     if (acpi_PkgStr(res, i++, sc->bix.serial, ACPI_CMBAT_MAXSTRLEN) != 0)
474             goto end;
475     if (acpi_PkgStr(res, i++, sc->bix.type, ACPI_CMBAT_MAXSTRLEN) != 0)
476             goto end;
477     if (acpi_PkgStr(res, i++, sc->bix.oeminfo, ACPI_CMBAT_MAXSTRLEN) != 0)
478             goto end;
479     if (ACPI_BIX_REV_MIN_CHECK(sc->bix.rev, ACPI_BIX_REV_1))
480             BIX_GETU32(scap);
481 #undef  BIX_GETU32
482 end:
483     AcpiOsFree(bix_buffer.Pointer);
484 }
485
486 static int
487 acpi_cmbat_bix(device_t dev, void *bix, size_t len)
488 {
489     struct acpi_cmbat_softc *sc;
490
491     if (len != sizeof(struct acpi_bix) &&
492         len != sizeof(struct acpi_bif))
493             return (-1);
494
495     sc = device_get_softc(dev);
496
497     /*
498      * Just copy the data.  The only value that should change is the
499      * last-full capacity, so we only update when we get a notify that says
500      * the info has changed.  Many systems apparently take a long time to
501      * process a _BI[FX] call so we avoid it if possible.
502      */
503     ACPI_SERIAL_BEGIN(cmbat);
504     memcpy(bix, &sc->bix, len);
505     ACPI_SERIAL_END(cmbat);
506
507     return (0);
508 }
509
510 static int
511 acpi_cmbat_bst(device_t dev, struct acpi_bst *bst)
512 {
513     struct acpi_cmbat_softc *sc;
514
515     sc = device_get_softc(dev);
516
517     ACPI_SERIAL_BEGIN(cmbat);
518     if (acpi_BatteryIsPresent(dev)) {
519         acpi_cmbat_get_bst(dev);
520         memcpy(bst, &sc->bst, sizeof(*bst));
521     } else
522         bst->state = ACPI_BATT_STAT_NOT_PRESENT;
523     ACPI_SERIAL_END(cmbat);
524
525     return (0);
526 }
527
528 static void
529 acpi_cmbat_init_battery(void *arg)
530 {
531     struct acpi_cmbat_softc *sc;
532     int         retry, valid;
533     device_t    dev;
534
535     dev = (device_t)arg;
536     ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
537         "battery enitialization start\n");
538
539     /*
540      * Try repeatedly to get valid data from the battery.  Since the
541      * embedded controller isn't always ready just after boot, we may have
542      * to wait a while.
543      */
544     for (retry = 0; retry < ACPI_CMBAT_RETRY_MAX; retry++, AcpiOsSleep(10000)) {
545         /*
546          * Batteries on DOCK can be ejected w/ DOCK during retrying.
547          *
548          * If there is a valid softc pointer the device may be in
549          * attaching, attached or detaching state. If the state is
550          * different from attached retry getting the device state
551          * until it becomes stable. This solves a race if the ACPI
552          * notification handler is called during attach, because
553          * device_is_attached() doesn't return non-zero until after
554          * the attach code has been executed.
555          */
556         ACPI_SERIAL_BEGIN(cmbat);
557         sc = device_get_softc(dev);
558         if (sc == NULL) {
559             ACPI_SERIAL_END(cmbat);
560             return;
561         }
562
563         if (!acpi_BatteryIsPresent(dev) || !device_is_attached(dev)) {
564             ACPI_SERIAL_END(cmbat);
565             continue;
566         }
567
568         /*
569          * Only query the battery if this is the first try or the specific
570          * type of info is still invalid.
571          */
572         if (retry == 0 || !acpi_battery_bst_valid(&sc->bst)) {
573             timespecclear(&sc->bst_lastupdated);
574             acpi_cmbat_get_bst(dev);
575         }
576         if (retry == 0 || !acpi_battery_bix_valid(&sc->bix))
577             acpi_cmbat_get_bix(dev);
578
579         valid = acpi_battery_bst_valid(&sc->bst) &&
580             acpi_battery_bix_valid(&sc->bix);
581         ACPI_SERIAL_END(cmbat);
582
583         if (valid)
584             break;
585     }
586
587     if (retry == ACPI_CMBAT_RETRY_MAX) {
588         ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
589             "battery initialization failed, giving up\n");
590     } else {
591         ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
592             "battery initialization done, tried %d times\n", retry + 1);
593     }
594 }