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