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