1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 * Copyright 2011 Joyent, Inc. All rights reserved.
25 * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
26 */
27
28 /*
29 * Power Button Driver
30 *
31 * This driver handles interrupt generated by the power button on
32 * platforms with "power" device node which has "button" property.
33 * Currently, these platforms are:
34 *
35 * ACPI-enabled x86/x64 platforms
36 * Ultra-5_10, Ultra-80, Sun-Blade-100, Sun-Blade-150,
37 * Sun-Blade-1500, Sun-Blade-2500,
38 * Sun-Fire-V210, Sun-Fire-V240, Netra-240
39 *
40 * Only one instance is allowed to attach. In order to know when
41 * an application that has opened the device is going away, a new
42 * minor clone is created for each open(9E) request. There are
43 * allocations for creating minor clones between 1 and 255. The ioctl
44 * interface is defined by pbio(7I) and approved as part of
45 * PSARC/1999/393 case.
46 */
47
48 #include <sys/types.h>
49 #include <sys/conf.h>
50 #include <sys/ddi.h>
51 #include <sys/sunddi.h>
52 #include <sys/ddi_impldefs.h>
53 #include <sys/cmn_err.h>
54 #include <sys/errno.h>
55 #include <sys/modctl.h>
56 #include <sys/open.h>
57 #include <sys/stat.h>
58 #include <sys/poll.h>
59 #include <sys/pbio.h>
60 #include <sys/sysevent/eventdefs.h>
61 #include <sys/sysevent/pwrctl.h>
62
63 #if defined(__sparc)
64 #include <sys/machsystm.h>
65 #endif
66
67 #ifdef ACPI_POWER_BUTTON
68
69 #include <sys/acpi/acpi.h>
70 #include <sys/acpica.h>
71
72 #else
73
74 #include <sys/epic.h>
75 /*
76 * Some #defs that must be here as they differ for power.c
77 * and epic.c
78 */
79 #define EPIC_REGS_OFFSET 0x00
80 #define EPIC_REGS_LEN 0x82
81
82
83 /*
84 * This flag, which is set for platforms, that have EPIC processor
85 * to process power button interrupt, helps in executing platform
86 * specific code.
87 */
88 static char hasEPIC = B_FALSE;
89 #endif /* ACPI_POWER_BUTTON */
90
91 /*
92 * Maximum number of clone minors that is allowed. This value
93 * is defined relatively low to save memory.
94 */
95 #define POWER_MAX_CLONE 256
96
97 /*
98 * Minor number is instance << 8 + clone minor from range 1-255; clone 0
99 * is reserved for "original" minor.
100 */
101 #define POWER_MINOR_TO_CLONE(minor) ((minor) & (POWER_MAX_CLONE - 1))
102
103 /*
104 * Power Button Abort Delay
105 */
106 #define ABORT_INCREMENT_DELAY 10
107
108 /*
109 * FWARC 2005/687: power device compatible property
110 */
111 #define POWER_DEVICE_TYPE "power-device-type"
112
113 /*
114 * Driver global variables
115 */
116 static void *power_state;
117 static int power_inst = -1;
118
119 static hrtime_t power_button_debounce = MSEC2NSEC(10);
120 static hrtime_t power_button_abort_interval = 1.5 * NANOSEC;
121 static int power_button_abort_presses = 3;
122 static int power_button_abort_enable = 1;
123 static int power_button_enable = 1;
124
125 static int power_button_pressed = 0;
126 static int power_button_cancel = 0;
127 static int power_button_timeouts = 0;
128 static int timeout_cancel = 0;
129 static int additional_presses = 0;
130
131 /*
132 * Function prototypes
133 */
134 static int power_attach(dev_info_t *, ddi_attach_cmd_t);
135 static int power_detach(dev_info_t *, ddi_detach_cmd_t);
136 static int power_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
137 static int power_open(dev_t *, int, int, cred_t *);
138 static int power_close(dev_t, int, int, cred_t *);
139 static int power_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
140 static int power_chpoll(dev_t, short, int, short *, struct pollhead **);
141 #ifndef ACPI_POWER_BUTTON
142 static uint_t power_high_intr(caddr_t);
143 #endif
144 static uint_t power_soft_intr(caddr_t);
145 static uint_t power_issue_shutdown(caddr_t);
146 static void power_timeout(caddr_t);
147 static void power_log_message(void);
148
149 /*
150 * Structure used in the driver
151 */
152 struct power_soft_state {
153 dev_info_t *dip; /* device info pointer */
154 kmutex_t power_mutex; /* mutex lock */
155 kmutex_t power_intr_mutex; /* interrupt mutex lock */
156 ddi_iblock_cookie_t soft_iblock_cookie; /* holds interrupt cookie */
157 ddi_iblock_cookie_t high_iblock_cookie; /* holds interrupt cookie */
158 ddi_softintr_t softintr_id; /* soft interrupt id */
159 uchar_t clones[POWER_MAX_CLONE]; /* array of minor clones */
160 int monitor_on; /* clone monitoring the button event */
161 /* clone 0 indicates no one is */
162 /* monitoring the button event */
163 pollhead_t pollhd; /* poll head struct */
164 int events; /* bit map of occured events */
165 int shutdown_pending; /* system shutdown in progress */
166 #ifdef ACPI_POWER_BUTTON
167 boolean_t fixed_attached; /* true means fixed is attached */
168 boolean_t gpe_attached; /* true means GPE is attached */
169 ACPI_HANDLE button_obj; /* handle to device power button */
170 #else
171 ddi_acc_handle_t power_rhandle; /* power button register handle */
172 uint8_t *power_btn_reg; /* power button register address */
173 uint8_t power_btn_bit; /* power button register bit */
174 boolean_t power_regs_mapped; /* flag to tell if regs mapped */
175 boolean_t power_btn_ioctl; /* flag to specify ioctl request */
176 #endif
177 };
178
179 static void power_gen_sysevent(struct power_soft_state *);
180
181 #ifdef ACPI_POWER_BUTTON
182 static int power_attach_acpi(struct power_soft_state *softsp);
183 static void power_detach_acpi(struct power_soft_state *softsp);
184 static UINT32 power_acpi_fixed_event(void *ctx);
185 #else
186 static int power_setup_regs(struct power_soft_state *softsp);
187 static void power_free_regs(struct power_soft_state *softsp);
188 #endif /* ACPI_POWER_BUTTON */
189
190 /*
191 * Configuration data structures
192 */
193 static struct cb_ops power_cb_ops = {
194 power_open, /* open */
195 power_close, /* close */
196 nodev, /* strategy */
197 nodev, /* print */
198 nodev, /* dump */
199 nodev, /* read */
200 nodev, /* write */
201 power_ioctl, /* ioctl */
202 nodev, /* devmap */
203 nodev, /* mmap */
204 nodev, /* segmap */
205 power_chpoll, /* poll */
206 ddi_prop_op, /* cb_prop_op */
207 NULL, /* streamtab */
208 D_MP | D_NEW, /* Driver compatibility flag */
209 CB_REV, /* rev */
210 nodev, /* cb_aread */
211 nodev /* cb_awrite */
212 };
213
214 static struct dev_ops power_ops = {
215 DEVO_REV, /* devo_rev, */
216 0, /* refcnt */
217 power_getinfo, /* getinfo */
218 nulldev, /* identify */
219 nulldev, /* probe */
220 power_attach, /* attach */
221 power_detach, /* detach */
222 nodev, /* reset */
223 &power_cb_ops, /* cb_ops */
224 (struct bus_ops *)NULL, /* bus_ops */
225 NULL, /* power */
226 ddi_quiesce_not_supported, /* devo_quiesce */
227 };
228
229 static struct modldrv modldrv = {
230 &mod_driverops, /* Type of module. This one is a driver */
231 "power button driver", /* name of module */
232 &power_ops, /* driver ops */
233 };
234
235 static struct modlinkage modlinkage = {
236 MODREV_1,
237 (void *)&modldrv,
238 NULL
239 };
240
241 /*
242 * These are the module initialization routines.
243 */
244
245 int
_init(void)246 _init(void)
247 {
248 int error;
249
250 if ((error = ddi_soft_state_init(&power_state,
251 sizeof (struct power_soft_state), 0)) != 0)
252 return (error);
253
254 if ((error = mod_install(&modlinkage)) != 0)
255 ddi_soft_state_fini(&power_state);
256
257 return (error);
258 }
259
260 int
_fini(void)261 _fini(void)
262 {
263 int error;
264
265 if ((error = mod_remove(&modlinkage)) == 0)
266 ddi_soft_state_fini(&power_state);
267
268 return (error);
269 }
270
271 int
_info(struct modinfo * modinfop)272 _info(struct modinfo *modinfop)
273 {
274 return (mod_info(&modlinkage, modinfop));
275 }
276
277 /*ARGSUSED*/
278 static int
power_getinfo(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)279 power_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
280 void **result)
281 {
282 struct power_soft_state *softsp;
283
284 if (power_inst == -1)
285 return (DDI_FAILURE);
286
287 switch (infocmd) {
288 case DDI_INFO_DEVT2DEVINFO:
289 if ((softsp = ddi_get_soft_state(power_state, power_inst))
290 == NULL)
291 return (DDI_FAILURE);
292 *result = (void *)softsp->dip;
293 return (DDI_SUCCESS);
294
295 case DDI_INFO_DEVT2INSTANCE:
296 *result = (void *)(uintptr_t)power_inst;
297 return (DDI_SUCCESS);
298
299 default:
300 return (DDI_FAILURE);
301 }
302 }
303
304 static int
power_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)305 power_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
306 {
307 struct power_soft_state *softsp;
308
309 switch (cmd) {
310 case DDI_ATTACH:
311 break;
312 case DDI_RESUME:
313 return (DDI_SUCCESS);
314 default:
315 return (DDI_FAILURE);
316 }
317
318 /*
319 * If the power node doesn't have "button" property, quietly
320 * fail to attach.
321 */
322 if (ddi_prop_exists(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
323 "button") == 0)
324 return (DDI_FAILURE);
325
326 if (power_inst != -1)
327 return (DDI_FAILURE);
328
329 power_inst = ddi_get_instance(dip);
330
331 if (ddi_soft_state_zalloc(power_state, power_inst) != DDI_SUCCESS)
332 return (DDI_FAILURE);
333
334 if (ddi_create_minor_node(dip, "power_button", S_IFCHR,
335 (power_inst << 8) + 0, "ddi_power_button", 0) != DDI_SUCCESS)
336 return (DDI_FAILURE);
337
338 softsp = ddi_get_soft_state(power_state, power_inst);
339 softsp->dip = dip;
340
341 #ifdef ACPI_POWER_BUTTON
342 (void) power_attach_acpi(softsp);
343 #else
344 if (power_setup_regs(softsp) != DDI_SUCCESS) {
345 cmn_err(CE_WARN, "power_attach: failed to setup registers");
346 goto error;
347 }
348
349 if (ddi_get_iblock_cookie(dip, 0,
350 &softsp->high_iblock_cookie) != DDI_SUCCESS) {
351 cmn_err(CE_WARN, "power_attach: ddi_get_soft_iblock_cookie "
352 "failed.");
353 goto error;
354 }
355 mutex_init(&softsp->power_intr_mutex, NULL, MUTEX_DRIVER,
356 softsp->high_iblock_cookie);
357
358 if (ddi_add_intr(dip, 0, &softsp->high_iblock_cookie, NULL,
359 power_high_intr, (caddr_t)softsp) != DDI_SUCCESS) {
360 cmn_err(CE_WARN, "power_attach: failed to add high-level "
361 " interrupt handler.");
362 mutex_destroy(&softsp->power_intr_mutex);
363 goto error;
364 }
365 #endif /* ACPI_POWER_BUTTON */
366
367 if (ddi_get_soft_iblock_cookie(dip, DDI_SOFTINT_LOW,
368 &softsp->soft_iblock_cookie) != DDI_SUCCESS) {
369 cmn_err(CE_WARN, "power_attach: ddi_get_soft_iblock_cookie "
370 "failed.");
371 mutex_destroy(&softsp->power_intr_mutex);
372 ddi_remove_intr(dip, 0, NULL);
373 goto error;
374 }
375
376 mutex_init(&softsp->power_mutex, NULL, MUTEX_DRIVER,
377 (void *)softsp->soft_iblock_cookie);
378
379 if (ddi_add_softintr(dip, DDI_SOFTINT_LOW, &softsp->softintr_id,
380 NULL, NULL, power_soft_intr, (caddr_t)softsp) != DDI_SUCCESS) {
381 cmn_err(CE_WARN, "power_attach: failed to add soft "
382 "interrupt handler.");
383 mutex_destroy(&softsp->power_mutex);
384 mutex_destroy(&softsp->power_intr_mutex);
385 ddi_remove_intr(dip, 0, NULL);
386 goto error;
387 }
388
389 ddi_report_dev(dip);
390
391 return (DDI_SUCCESS);
392
393 error:
394 #ifdef ACPI_POWER_BUTTON
395 /*
396 * detach ACPI power button
397 */
398 power_detach_acpi(softsp);
399 #else
400 power_free_regs(softsp);
401 #endif /* ACPI_POWER_BUTTON */
402 ddi_remove_minor_node(dip, "power_button");
403 ddi_soft_state_free(power_state, power_inst);
404 return (DDI_FAILURE);
405 }
406
407 /*ARGSUSED*/
408 /*
409 * This driver doesn't detach.
410 */
411 static int
power_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)412 power_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
413 {
414 /*
415 * Since the "power" node has "reg" property, as part of
416 * the suspend operation, detach(9E) entry point is called.
417 * There is no state to save, since this register is used
418 * by OBP to power off the system and the state of the
419 * power off is preserved by hardware.
420 */
421 return ((cmd == DDI_SUSPEND) ? DDI_SUCCESS :
422 DDI_FAILURE);
423 }
424
425
426 #ifndef ACPI_POWER_BUTTON
427 /*
428 * Handler for the high-level interrupt.
429 */
430 static uint_t
power_high_intr(caddr_t arg)431 power_high_intr(caddr_t arg)
432 {
433 struct power_soft_state *softsp = (struct power_soft_state *)arg;
434 ddi_acc_handle_t hdl = softsp->power_rhandle;
435 uint8_t reg;
436
437 hrtime_t tstamp;
438 static hrtime_t o_tstamp = 0;
439 static hrtime_t power_button_tstamp = 0;
440 static int power_button_cnt;
441
442 if (softsp->power_regs_mapped) {
443 mutex_enter(&softsp->power_intr_mutex);
444
445 /* Check if power button interrupt is delivered by EPIC HW */
446 if (hasEPIC) {
447 /* read isr - first issue command */
448 EPIC_WR(hdl, softsp->power_btn_reg,
449 EPIC_ATOM_INTR_READ);
450 /* next, read the reg */
451 EPIC_RD(hdl, softsp->power_btn_reg, reg);
452
453 if (reg & EPIC_FIRE_INTERRUPT) { /* PB pressed */
454 /* clear the interrupt */
455 EPIC_WR(hdl, softsp->power_btn_reg,
456 EPIC_ATOM_INTR_CLEAR);
457 } else {
458 if (!softsp->power_btn_ioctl) {
459 mutex_exit(&softsp->power_intr_mutex);
460 return (DDI_INTR_CLAIMED);
461 }
462 softsp->power_btn_ioctl = B_FALSE;
463 }
464 } else {
465 reg = ddi_get8(hdl, softsp->power_btn_reg);
466 if (reg & softsp->power_btn_bit) {
467 reg &= softsp->power_btn_bit;
468 ddi_put8(hdl, softsp->power_btn_reg, reg);
469 (void) ddi_get8(hdl, softsp->power_btn_reg);
470 } else {
471 if (!softsp->power_btn_ioctl) {
472 mutex_exit(&softsp->power_intr_mutex);
473 return (DDI_INTR_CLAIMED);
474 }
475 softsp->power_btn_ioctl = B_FALSE;
476 }
477 }
478 mutex_exit(&softsp->power_intr_mutex);
479 }
480
481 tstamp = gethrtime();
482
483 /* need to deal with power button debounce */
484 if (o_tstamp && (tstamp - o_tstamp) < power_button_debounce) {
485 o_tstamp = tstamp;
486 return (DDI_INTR_CLAIMED);
487 }
488 o_tstamp = tstamp;
489
490 power_button_cnt++;
491
492 mutex_enter(&softsp->power_intr_mutex);
493 power_button_pressed++;
494 mutex_exit(&softsp->power_intr_mutex);
495
496 /*
497 * If power button abort is enabled and power button was pressed
498 * power_button_abort_presses times within power_button_abort_interval
499 * then call abort_sequence_enter();
500 */
501 if (power_button_abort_enable) {
502 if (power_button_abort_presses == 1 ||
503 tstamp < (power_button_tstamp +
504 power_button_abort_interval)) {
505 if (power_button_cnt == power_button_abort_presses) {
506 mutex_enter(&softsp->power_intr_mutex);
507 power_button_cancel += power_button_timeouts;
508 power_button_pressed = 0;
509 mutex_exit(&softsp->power_intr_mutex);
510 power_button_cnt = 0;
511 abort_sequence_enter("Power Button Abort");
512 return (DDI_INTR_CLAIMED);
513 }
514 } else {
515 power_button_cnt = 1;
516 power_button_tstamp = tstamp;
517 }
518 }
519
520 if (!power_button_enable)
521 return (DDI_INTR_CLAIMED);
522
523 /* post softint to issue timeout for power button action */
524 if (softsp->softintr_id != NULL)
525 ddi_trigger_softintr(softsp->softintr_id);
526
527 return (DDI_INTR_CLAIMED);
528 }
529 #endif /* ifndef ACPI_POWER_BUTTON */
530
531 /*
532 * Handle the softints....
533 *
534 * If only one softint is posted for several button presses, record
535 * the number of additional presses just incase this was actually not quite
536 * an Abort sequence so that we can log this event later.
537 *
538 * Issue a timeout with a duration being a fraction larger than
539 * the specified Abort interval inorder to perform a power down if required.
540 */
541 static uint_t
power_soft_intr(caddr_t arg)542 power_soft_intr(caddr_t arg)
543 {
544 struct power_soft_state *softsp = (struct power_soft_state *)arg;
545
546 if (!power_button_abort_enable)
547 return (power_issue_shutdown(arg));
548
549 mutex_enter(&softsp->power_intr_mutex);
550 if (!power_button_pressed) {
551 mutex_exit(&softsp->power_intr_mutex);
552 return (DDI_INTR_CLAIMED);
553 }
554
555 /*
556 * Schedule a timeout to do the necessary
557 * work for shutdown, only one timeout for
558 * n presses if power button was pressed
559 * more than once before softint fired
560 */
561 if (power_button_pressed > 1)
562 additional_presses += power_button_pressed - 1;
563
564 timeout_cancel = 0;
565 power_button_pressed = 0;
566 power_button_timeouts++;
567 mutex_exit(&softsp->power_intr_mutex);
568 (void) timeout((void(*)(void *))power_timeout,
569 softsp, NSEC_TO_TICK(power_button_abort_interval) +
570 ABORT_INCREMENT_DELAY);
571
572 return (DDI_INTR_CLAIMED);
573 }
574
575 /*
576 * Upon receiving a timeout the following is determined:
577 *
578 * If an Abort sequence was issued, then we cancel all outstanding timeouts
579 * and additional presses prior to the Abort sequence.
580 *
581 * If we had multiple timeouts issued and the abort sequence was not met,
582 * then we had more than one button press to power down the machine. We
583 * were probably trying to issue an abort. So log a message indicating this
584 * and cancel all outstanding timeouts.
585 *
586 * If we had just one timeout and the abort sequence was not met then
587 * we really did want to power down the machine, so call power_issue_shutdown()
588 * to do the work and schedule a power down
589 */
590 static void
power_timeout(caddr_t arg)591 power_timeout(caddr_t arg)
592 {
593 struct power_soft_state *softsp = (struct power_soft_state *)arg;
594 static int first = 0;
595
596 /*
597 * Abort was generated cancel all outstanding power
598 * button timeouts
599 */
600 mutex_enter(&softsp->power_intr_mutex);
601 if (power_button_cancel) {
602 power_button_cancel--;
603 power_button_timeouts--;
604 if (!first) {
605 first++;
606 additional_presses = 0;
607 }
608 mutex_exit(&softsp->power_intr_mutex);
609 return;
610 }
611 first = 0;
612
613 /*
614 * We get here if the timeout(s) have fired and they were
615 * not issued prior to an abort.
616 *
617 * If we had more than one press in the interval we were
618 * probably trying to issue an abort, but didnt press the
619 * required number within the interval. Hence cancel all
620 * timeouts and do not continue towards shutdown.
621 */
622 if (!timeout_cancel) {
623 timeout_cancel = power_button_timeouts +
624 additional_presses;
625
626 power_button_timeouts--;
627 if (!power_button_timeouts)
628 additional_presses = 0;
629
630 if (timeout_cancel > 1) {
631 mutex_exit(&softsp->power_intr_mutex);
632 cmn_err(CE_NOTE, "Power Button pressed "
633 "%d times, cancelling all requests",
634 timeout_cancel);
635 return;
636 }
637 mutex_exit(&softsp->power_intr_mutex);
638
639 /* Go and do the work to request shutdown */
640 (void) power_issue_shutdown((caddr_t)softsp);
641 return;
642 }
643
644 power_button_timeouts--;
645 if (!power_button_timeouts)
646 additional_presses = 0;
647 mutex_exit(&softsp->power_intr_mutex);
648 }
649
650 #ifdef ACPI_POWER_BUTTON
651 static void
do_shutdown(void)652 do_shutdown(void)
653 {
654 proc_t *initpp;
655
656 /*
657 * If we're still booting and init(1) isn't set up yet, simply halt.
658 */
659 mutex_enter(&pidlock);
660 initpp = prfind(P_INITPID);
661 mutex_exit(&pidlock);
662 if (initpp == NULL) {
663 extern void halt(char *);
664 halt("Power off the System"); /* just in case */
665 }
666
667 /*
668 * else, graceful shutdown with inittab and all getting involved
669 */
670 psignal(initpp, SIGPWR);
671 }
672 #endif
673
674 static uint_t
power_issue_shutdown(caddr_t arg)675 power_issue_shutdown(caddr_t arg)
676 {
677 struct power_soft_state *softsp = (struct power_soft_state *)arg;
678
679 mutex_enter(&softsp->power_mutex);
680 softsp->events |= PB_BUTTON_PRESS;
681 if (softsp->monitor_on != 0) {
682 mutex_exit(&softsp->power_mutex);
683 pollwakeup(&softsp->pollhd, POLLRDNORM);
684 pollwakeup(&softsp->pollhd, POLLIN);
685 power_gen_sysevent(softsp);
686 return (DDI_INTR_CLAIMED);
687 }
688
689 if (!softsp->shutdown_pending) {
690 cmn_err(CE_WARN, "Power off requested from power button or "
691 "SC, powering down the system!");
692 softsp->shutdown_pending = 1;
693 do_shutdown();
694
695 /*
696 * Wait a while for "do_shutdown()" to shut down the system
697 * before logging an error message.
698 */
699 (void) timeout((void(*)(void *))power_log_message, NULL,
700 100 * hz);
701 }
702 mutex_exit(&softsp->power_mutex);
703
704 return (DDI_INTR_CLAIMED);
705 }
706
707 static void
power_gen_sysevent(struct power_soft_state * softsp)708 power_gen_sysevent(struct power_soft_state *softsp)
709 {
710 nvlist_t *attr_list = NULL;
711 int err;
712 char pathname[MAXPATHLEN];
713 char hid[9] = "\0";
714
715 /* Allocate and build sysevent attribute list */
716 err = nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE, DDI_NOSLEEP);
717 if (err != 0) {
718 cmn_err(CE_WARN,
719 "cannot allocate memory for sysevent attributes\n");
720 return;
721 }
722
723 #ifdef ACPI_POWER_BUTTON
724 /* Only control method power button has HID */
725 if (softsp->gpe_attached) {
726 (void) strlcpy(hid, "PNP0C0C", sizeof (hid));
727 }
728 #endif
729
730 err = nvlist_add_string(attr_list, PWRCTL_DEV_HID, hid);
731 if (err != 0) {
732 cmn_err(CE_WARN,
733 "Failed to add attr [%s] for %s/%s event",
734 PWRCTL_DEV_HID, EC_PWRCTL, ESC_PWRCTL_POWER_BUTTON);
735 nvlist_free(attr_list);
736 return;
737 }
738
739 (void) ddi_pathname(softsp->dip, pathname);
740 err = nvlist_add_string(attr_list, PWRCTL_DEV_PHYS_PATH, pathname);
741 if (err != 0) {
742 cmn_err(CE_WARN,
743 "Failed to add attr [%s] for %s/%s event",
744 PWRCTL_DEV_PHYS_PATH, EC_PWRCTL, ESC_PWRCTL_POWER_BUTTON);
745 nvlist_free(attr_list);
746 return;
747 }
748
749 /* Generate/log sysevent */
750 err = ddi_log_sysevent(softsp->dip, DDI_VENDOR_SUNW, EC_PWRCTL,
751 ESC_PWRCTL_POWER_BUTTON, attr_list, NULL, DDI_NOSLEEP);
752 if (err != DDI_SUCCESS) {
753 cmn_err(CE_WARN,
754 "cannot log sysevent, err code %x\n", err);
755 }
756
757 nvlist_free(attr_list);
758 }
759
760 /*
761 * Open the device.
762 */
763 /*ARGSUSED*/
764 static int
power_open(dev_t * devp,int openflags,int otyp,cred_t * credp)765 power_open(dev_t *devp, int openflags, int otyp, cred_t *credp)
766 {
767 struct power_soft_state *softsp;
768 int clone;
769
770 if (otyp != OTYP_CHR)
771 return (EINVAL);
772
773 if ((softsp = ddi_get_soft_state(power_state, power_inst)) ==
774 NULL)
775 return (ENXIO);
776
777 mutex_enter(&softsp->power_mutex);
778 for (clone = 1; clone < POWER_MAX_CLONE; clone++)
779 if (!softsp->clones[clone])
780 break;
781
782 if (clone == POWER_MAX_CLONE) {
783 cmn_err(CE_WARN, "power_open: No more allocation left "
784 "to create a clone minor.");
785 mutex_exit(&softsp->power_mutex);
786 return (ENXIO);
787 }
788
789 *devp = makedevice(getmajor(*devp), (power_inst << 8) + clone);
790 softsp->clones[clone] = 1;
791 mutex_exit(&softsp->power_mutex);
792
793 return (0);
794 }
795
796 /*
797 * Close the device.
798 */
799 /*ARGSUSED*/
800 static int
power_close(dev_t dev,int openflags,int otyp,cred_t * credp)801 power_close(dev_t dev, int openflags, int otyp, cred_t *credp)
802 {
803 struct power_soft_state *softsp;
804 int clone;
805
806 if (otyp != OTYP_CHR)
807 return (EINVAL);
808
809 if ((softsp = ddi_get_soft_state(power_state, power_inst)) ==
810 NULL)
811 return (ENXIO);
812
813 clone = POWER_MINOR_TO_CLONE(getminor(dev));
814 mutex_enter(&softsp->power_mutex);
815 if (softsp->monitor_on == clone)
816 softsp->monitor_on = 0;
817 softsp->clones[clone] = 0;
818 mutex_exit(&softsp->power_mutex);
819
820 return (0);
821 }
822
823 /*ARGSUSED*/
824 static int
power_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * cred_p,int * rval_p)825 power_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cred_p,
826 int *rval_p)
827 {
828 struct power_soft_state *softsp;
829 int clone;
830
831 if ((softsp = ddi_get_soft_state(power_state, power_inst)) ==
832 NULL)
833 return (ENXIO);
834
835 clone = POWER_MINOR_TO_CLONE(getminor(dev));
836 switch (cmd) {
837 case PB_BEGIN_MONITOR:
838 mutex_enter(&softsp->power_mutex);
839 if (softsp->monitor_on) {
840 mutex_exit(&softsp->power_mutex);
841 return (EBUSY);
842 }
843 softsp->monitor_on = clone;
844 mutex_exit(&softsp->power_mutex);
845 return (0);
846
847 case PB_END_MONITOR:
848 mutex_enter(&softsp->power_mutex);
849
850 /*
851 * If PB_END_MONITOR is called without first
852 * calling PB_BEGIN_MONITOR, an error will be
853 * returned.
854 */
855 if (!softsp->monitor_on) {
856 mutex_exit(&softsp->power_mutex);
857 return (ENXIO);
858 }
859
860 /*
861 * This clone is not monitoring the button.
862 */
863 if (softsp->monitor_on != clone) {
864 mutex_exit(&softsp->power_mutex);
865 return (EINVAL);
866 }
867 softsp->monitor_on = 0;
868 mutex_exit(&softsp->power_mutex);
869 return (0);
870
871 case PB_GET_EVENTS:
872 mutex_enter(&softsp->power_mutex);
873 if (ddi_copyout((void *)&softsp->events, (void *)arg,
874 sizeof (int), mode) != 0) {
875 mutex_exit(&softsp->power_mutex);
876 return (EFAULT);
877 }
878
879 /*
880 * This ioctl returned the events detected since last
881 * call. Note that any application can get the events
882 * and clear the event register.
883 */
884 softsp->events = 0;
885 mutex_exit(&softsp->power_mutex);
886 return (0);
887
888 /*
889 * This ioctl is used by the test suite.
890 */
891 case PB_CREATE_BUTTON_EVENT:
892 #ifdef ACPI_POWER_BUTTON
893 (UINT32)power_acpi_fixed_event((void *)softsp);
894 #else
895 if (softsp->power_regs_mapped) {
896 mutex_enter(&softsp->power_intr_mutex);
897 softsp->power_btn_ioctl = B_TRUE;
898 mutex_exit(&softsp->power_intr_mutex);
899 }
900 (void) power_high_intr((caddr_t)softsp);
901 #endif /* ACPI_POWER_BUTTON */
902 return (0);
903
904 default:
905 return (ENOTTY);
906 }
907 }
908
909 /*ARGSUSED*/
910 static int
power_chpoll(dev_t dev,short events,int anyyet,short * reventsp,struct pollhead ** phpp)911 power_chpoll(dev_t dev, short events, int anyyet,
912 short *reventsp, struct pollhead **phpp)
913 {
914 struct power_soft_state *softsp;
915
916 if ((softsp = ddi_get_soft_state(power_state, power_inst)) == NULL)
917 return (ENXIO);
918
919 mutex_enter(&softsp->power_mutex);
920 *reventsp = 0;
921 if (softsp->events)
922 *reventsp = POLLRDNORM|POLLIN;
923 else {
924 if (!anyyet)
925 *phpp = &softsp->pollhd;
926 }
927 mutex_exit(&softsp->power_mutex);
928
929 return (0);
930 }
931
932 static void
power_log_message(void)933 power_log_message(void)
934 {
935 struct power_soft_state *softsp;
936
937 if ((softsp = ddi_get_soft_state(power_state, power_inst)) == NULL) {
938 cmn_err(CE_WARN, "Failed to get internal state!");
939 return;
940 }
941
942 mutex_enter(&softsp->power_mutex);
943 softsp->shutdown_pending = 0;
944 cmn_err(CE_WARN, "Failed to shut down the system!");
945 mutex_exit(&softsp->power_mutex);
946 }
947
948 #ifdef ACPI_POWER_BUTTON
949 /*
950 *
951 */
952 /*ARGSUSED*/
953 static ACPI_STATUS
acpi_device(ACPI_HANDLE obj,UINT32 nesting,void * context,void ** rv)954 acpi_device(ACPI_HANDLE obj, UINT32 nesting, void *context, void **rv)
955 {
956
957 *((ACPI_HANDLE *)context) = obj;
958 return (AE_OK);
959 }
960
961 /*
962 *
963 */
964 static ACPI_HANDLE
probe_acpi_pwrbutton()965 probe_acpi_pwrbutton()
966 {
967 ACPI_HANDLE obj = NULL;
968
969 (void) AcpiGetDevices("PNP0C0C", acpi_device, (void *)&obj, NULL);
970 return (obj);
971 }
972
973 static UINT32
power_acpi_fixed_event(void * ctx)974 power_acpi_fixed_event(void *ctx)
975 {
976
977 mutex_enter(&((struct power_soft_state *)ctx)->power_intr_mutex);
978 power_button_pressed++;
979 mutex_exit(&((struct power_soft_state *)ctx)->power_intr_mutex);
980
981 /* post softint to issue timeout for power button action */
982 if (((struct power_soft_state *)ctx)->softintr_id != NULL)
983 ddi_trigger_softintr(
984 ((struct power_soft_state *)ctx)->softintr_id);
985
986 return (AE_OK);
987 }
988
989 /*ARGSUSED*/
990 static void
power_acpi_notify_event(ACPI_HANDLE obj,UINT32 val,void * ctx)991 power_acpi_notify_event(ACPI_HANDLE obj, UINT32 val, void *ctx)
992 {
993 if (val == 0x80)
994 (void) power_acpi_fixed_event(ctx);
995 }
996
997 /*
998 *
999 */
1000 static int
power_probe_method_button(struct power_soft_state * softsp)1001 power_probe_method_button(struct power_soft_state *softsp)
1002 {
1003 ACPI_HANDLE button_obj;
1004
1005 button_obj = probe_acpi_pwrbutton();
1006 softsp->button_obj = button_obj; /* remember obj */
1007 if ((button_obj != NULL) &&
1008 (AcpiInstallNotifyHandler(button_obj, ACPI_DEVICE_NOTIFY,
1009 power_acpi_notify_event, (void*)softsp) == AE_OK))
1010 return (1);
1011 return (0);
1012 }
1013
1014 /*
1015 *
1016 */
1017 static int
power_probe_fixed_button(struct power_soft_state * softsp)1018 power_probe_fixed_button(struct power_soft_state *softsp)
1019 {
1020 ACPI_TABLE_FADT *fadt;
1021
1022 if (AcpiGetTable(ACPI_SIG_FADT, 1, (ACPI_TABLE_HEADER **) &fadt) !=
1023 AE_OK)
1024 return (0);
1025
1026 if ((fadt->Flags & ACPI_FADT_POWER_BUTTON) == 0) {
1027 if (AcpiInstallFixedEventHandler(ACPI_EVENT_POWER_BUTTON,
1028 power_acpi_fixed_event, (void *)softsp) == AE_OK)
1029 return (1);
1030 }
1031 return (0);
1032 }
1033
1034
1035 /*
1036 *
1037 */
1038 static int
power_attach_acpi(struct power_soft_state * softsp)1039 power_attach_acpi(struct power_soft_state *softsp)
1040 {
1041
1042 /*
1043 * If we've attached anything already, return an error
1044 */
1045 if ((softsp->gpe_attached) || (softsp->fixed_attached))
1046 return (DDI_FAILURE);
1047
1048 /*
1049 * attempt to attach both a fixed-event handler and a GPE
1050 * handler; remember what we got
1051 */
1052 softsp->fixed_attached = (power_probe_fixed_button(softsp) != 0);
1053 softsp->gpe_attached = (power_probe_method_button(softsp) != 0);
1054
1055 /*
1056 * If we've attached anything now, return success
1057 */
1058 if ((softsp->gpe_attached) || (softsp->fixed_attached))
1059 return (DDI_SUCCESS);
1060
1061 return (DDI_FAILURE);
1062 }
1063
1064 /*
1065 *
1066 */
1067 static void
power_detach_acpi(struct power_soft_state * softsp)1068 power_detach_acpi(struct power_soft_state *softsp)
1069 {
1070 if (softsp->gpe_attached) {
1071 if (AcpiRemoveNotifyHandler(softsp->button_obj,
1072 ACPI_DEVICE_NOTIFY, power_acpi_notify_event) != AE_OK)
1073 cmn_err(CE_WARN, "!power: failed to remove Notify"
1074 " handler");
1075 }
1076
1077 if (softsp->fixed_attached) {
1078 if (AcpiRemoveFixedEventHandler(ACPI_EVENT_POWER_BUTTON,
1079 power_acpi_fixed_event) != AE_OK)
1080 cmn_err(CE_WARN, "!power: failed to remove Power"
1081 " Button handler");
1082 }
1083 }
1084
1085 #else
1086 /*
1087 * Code for platforms that have EPIC processor for processing power
1088 * button interrupts.
1089 */
1090 static int
power_setup_epic_regs(dev_info_t * dip,struct power_soft_state * softsp)1091 power_setup_epic_regs(dev_info_t *dip, struct power_soft_state *softsp)
1092 {
1093 ddi_device_acc_attr_t attr;
1094 uint8_t *reg_base;
1095
1096 attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
1097 attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
1098 attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
1099 if (ddi_regs_map_setup(dip, 0, (caddr_t *)®_base,
1100 EPIC_REGS_OFFSET, EPIC_REGS_LEN, &attr,
1101 &softsp->power_rhandle) != DDI_SUCCESS) {
1102 return (DDI_FAILURE);
1103 }
1104
1105 softsp->power_btn_reg = reg_base;
1106 softsp->power_regs_mapped = B_TRUE;
1107
1108 /* Clear power button interrupt first */
1109 EPIC_WR(softsp->power_rhandle, softsp->power_btn_reg,
1110 EPIC_ATOM_INTR_CLEAR);
1111
1112 /* Enable EPIC interrupt for power button single press event */
1113 EPIC_WR(softsp->power_rhandle, softsp->power_btn_reg,
1114 EPIC_ATOM_INTR_ENABLE);
1115
1116 /*
1117 * At this point, EPIC interrupt processing is fully initialised.
1118 */
1119 hasEPIC = B_TRUE;
1120 return (DDI_SUCCESS);
1121 }
1122
1123 /*
1124 *
1125 * power button register definitions for acpi register on m1535d
1126 */
1127 #define M1535D_PWR_BTN_REG_01 0x1
1128 #define M1535D_PWR_BTN_EVENT_FLAG 0x1
1129
1130 static int
power_setup_m1535_regs(dev_info_t * dip,struct power_soft_state * softsp)1131 power_setup_m1535_regs(dev_info_t *dip, struct power_soft_state *softsp)
1132 {
1133 ddi_device_acc_attr_t attr;
1134 uint8_t *reg_base;
1135
1136 attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
1137 attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
1138 attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
1139 if (ddi_regs_map_setup(dip, 0, (caddr_t *)®_base, 0, 0, &attr,
1140 &softsp->power_rhandle) != DDI_SUCCESS) {
1141 return (DDI_FAILURE);
1142 }
1143 softsp->power_btn_reg = ®_base[M1535D_PWR_BTN_REG_01];
1144 softsp->power_btn_bit = M1535D_PWR_BTN_EVENT_FLAG;
1145 softsp->power_regs_mapped = B_TRUE;
1146 return (DDI_SUCCESS);
1147 }
1148
1149 /*
1150 * MBC Fire/SSI Interrupt Status Register definitions
1151 */
1152 #define FIRE_SSI_ISR 0x0
1153 #define FIRE_SSI_INTR_ENA 0x8
1154 #define FIRE_SSI_SHUTDOWN_REQ 0x4
1155
1156 static int
power_setup_mbc_regs(dev_info_t * dip,struct power_soft_state * softsp)1157 power_setup_mbc_regs(dev_info_t *dip, struct power_soft_state *softsp)
1158 {
1159 ddi_device_acc_attr_t attr;
1160 uint8_t *reg_base;
1161 ddi_acc_handle_t hdl;
1162 uint8_t reg;
1163
1164 attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
1165 attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
1166 attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
1167 if (ddi_regs_map_setup(dip, 0, (caddr_t *)®_base, 0, 0, &attr,
1168 &softsp->power_rhandle) != DDI_SUCCESS) {
1169 return (DDI_FAILURE);
1170 }
1171 softsp->power_btn_reg = ®_base[FIRE_SSI_ISR];
1172 softsp->power_btn_bit = FIRE_SSI_SHUTDOWN_REQ;
1173 hdl = softsp->power_rhandle;
1174 /*
1175 * Clear MBC Fire Power Button interrupt, if set.
1176 */
1177 reg = ddi_get8(hdl, softsp->power_btn_reg);
1178 if (reg & softsp->power_btn_bit) {
1179 reg &= softsp->power_btn_bit;
1180 ddi_put8(hdl, softsp->power_btn_reg, reg);
1181 (void) ddi_get8(hdl, softsp->power_btn_reg);
1182 }
1183 /*
1184 * Enable MBC Fire Power Button interrupt.
1185 */
1186 reg = ddi_get8(hdl, ®_base[FIRE_SSI_INTR_ENA]);
1187 reg |= FIRE_SSI_SHUTDOWN_REQ;
1188 ddi_put8(hdl, ®_base[FIRE_SSI_INTR_ENA], reg);
1189
1190 softsp->power_regs_mapped = B_TRUE;
1191
1192 return (DDI_SUCCESS);
1193 }
1194
1195 /*
1196 * Setup register map for the power button
1197 * NOTE:- we only map registers for platforms if
1198 * the OBP power device has any of the following
1199 * properties:
1200 *
1201 * a) Boston: power-device-type set to "SUNW,mbc"
1202 * b) Seattle: power-device-type set to "SUNW,pic18lf65j10"
1203 * c) Chalupa: compatible set to "ali1535d+-power"
1204 *
1205 * Cases (a) and (b) are defined in FWARC 2005/687.
1206 * If none of the above conditions are true, then we
1207 * do not need to map in any registers, and this
1208 * function can simply return DDI_SUCCESS.
1209 */
1210 static int
power_setup_regs(struct power_soft_state * softsp)1211 power_setup_regs(struct power_soft_state *softsp)
1212 {
1213 char *binding_name;
1214 char *power_type = NULL;
1215 int retval = DDI_SUCCESS;
1216
1217 softsp->power_regs_mapped = B_FALSE;
1218 softsp->power_btn_ioctl = B_FALSE;
1219 binding_name = ddi_binding_name(softsp->dip);
1220 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, softsp->dip,
1221 DDI_PROP_DONTPASS, POWER_DEVICE_TYPE,
1222 &power_type) == DDI_PROP_SUCCESS) {
1223 if (strcmp(power_type, "SUNW,mbc") == 0) {
1224 retval = power_setup_mbc_regs(softsp->dip, softsp);
1225 } else if (strcmp(power_type, "SUNW,pic18lf65j10") == 0) {
1226 retval = power_setup_epic_regs(softsp->dip, softsp);
1227 } else {
1228 cmn_err(CE_WARN, "unexpected power-device-type: %s\n",
1229 power_type);
1230 retval = DDI_FAILURE;
1231 }
1232 ddi_prop_free(power_type);
1233 } else if (strcmp(binding_name, "ali1535d+-power") == 0) {
1234 retval = power_setup_m1535_regs(softsp->dip, softsp);
1235 }
1236
1237 /*
1238 * If power-device-type does not exist AND the binding name is not
1239 * "ali1535d+-power", that means there is no additional HW and hence
1240 * no extra processing is necessary. In that case, retval should still
1241 * be set to its initial value of DDI_SUCCESS.
1242 */
1243 return (retval);
1244 }
1245
1246 static void
power_free_regs(struct power_soft_state * softsp)1247 power_free_regs(struct power_soft_state *softsp)
1248 {
1249 if (softsp->power_regs_mapped)
1250 ddi_regs_map_free(&softsp->power_rhandle);
1251 }
1252 #endif /* ACPI_POWER_BUTTON */
1253