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