1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22/*
23 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27#include <sys/types.h>
28#include <sys/smp_impldefs.h>
29#include <sys/promif.h>
30
31#include <sys/kmem.h>
32#include <sys/archsystm.h>
33#include <sys/cpuvar.h>
34#include <sys/pte.h>
35#include <vm/seg_kmem.h>
36#include <sys/epm.h>
37#include <sys/cpr.h>
38#include <sys/machsystm.h>
39#include <sys/clock.h>
40
41#include <sys/cpr_wakecode.h>
42#include <sys/acpi/acpi.h>
43
44#ifdef OLDPMCODE
45#include "acpi.h"
46#endif
47
48#include	<sys/x86_archext.h>
49#include	<sys/reboot.h>
50#include	<sys/cpu_module.h>
51#include	<sys/kdi.h>
52
53/*
54 * S3 stuff
55 */
56
57int acpi_rtc_wake = 0x0;		/* wake in N seconds */
58
59#if 0	/* debug */
60static uint8_t	branchbuf[64 * 1024];	/* for the HDT branch trace stuff */
61#endif	/* debug */
62
63extern int boothowto;
64
65#define	BOOTCPU	0	/* cpu 0 is always the boot cpu */
66
67extern void		kernel_wc_code(void);
68extern tod_ops_t	*tod_ops;
69extern int flushes_require_xcalls;
70extern int tsc_gethrtime_enable;
71
72extern cpuset_t cpu_ready_set;
73extern void *(*cpu_pause_func)(void *);
74
75
76
77/*
78 * This is what we've all been waiting for!
79 */
80int
81acpi_enter_sleepstate(s3a_t *s3ap)
82{
83	ACPI_PHYSICAL_ADDRESS	wakephys = s3ap->s3a_wakephys;
84	caddr_t			wakevirt = rm_platter_va;
85	/*LINTED*/
86	wakecode_t		*wp = (wakecode_t *)wakevirt;
87	uint_t			Sx = s3ap->s3a_state;
88
89	PT(PT_SWV);
90	/* Set waking vector */
91	if (AcpiSetFirmwareWakingVector(wakephys) != AE_OK) {
92		PT(PT_SWV_FAIL);
93		PMD(PMD_SX, ("Can't SetFirmwareWakingVector(%lx)\n",
94		    (long)wakephys))
95		goto insomnia;
96	}
97
98	PT(PT_EWE);
99	/* Enable wake events */
100	if (AcpiEnableEvent(ACPI_EVENT_POWER_BUTTON, 0) != AE_OK) {
101		PT(PT_EWE_FAIL);
102		PMD(PMD_SX, ("Can't EnableEvent(POWER_BUTTON)\n"))
103	}
104	if (acpi_rtc_wake > 0) {
105		/* clear the RTC bit first */
106		(void) AcpiWriteBitRegister(ACPI_BITREG_RT_CLOCK_STATUS, 1);
107		PT(PT_RTCW);
108		if (AcpiEnableEvent(ACPI_EVENT_RTC, 0) != AE_OK) {
109			PT(PT_RTCW_FAIL);
110			PMD(PMD_SX, ("Can't EnableEvent(RTC)\n"))
111		}
112
113		/*
114		 * Set RTC to wake us in a wee while.
115		 */
116		mutex_enter(&tod_lock);
117		PT(PT_TOD);
118		TODOP_SETWAKE(tod_ops, acpi_rtc_wake);
119		mutex_exit(&tod_lock);
120	}
121
122	/*
123	 * Prepare for sleep ... could've done this earlier?
124	 */
125	PT(PT_SXP);
126	PMD(PMD_SX, ("Calling AcpiEnterSleepStatePrep(%d) ...\n", Sx))
127	if (AcpiEnterSleepStatePrep(Sx) != AE_OK) {
128		PMD(PMD_SX, ("... failed\n!"))
129		goto insomnia;
130	}
131
132	switch (s3ap->s3a_test_point) {
133	case DEVICE_SUSPEND_TO_RAM:
134	case FORCE_SUSPEND_TO_RAM:
135	case LOOP_BACK_PASS:
136		return (0);
137	case LOOP_BACK_FAIL:
138		return (1);
139	default:
140		ASSERT(s3ap->s3a_test_point == LOOP_BACK_NONE);
141	}
142
143	/*
144	 * Tell the hardware to sleep.
145	 */
146	PT(PT_SXE);
147	PMD(PMD_SX, ("Calling AcpiEnterSleepState(%d) ...\n", Sx))
148	if (AcpiEnterSleepState(Sx) != AE_OK) {
149		PT(PT_SXE_FAIL);
150		PMD(PMD_SX, ("... failed!\n"))
151	}
152
153insomnia:
154	PT(PT_INSOM);
155	/* cleanup is done in the caller */
156	return (1);
157}
158
159int
160acpi_exit_sleepstate(s3a_t *s3ap)
161{
162	int Sx = s3ap->s3a_state;
163
164	PT(PT_WOKE);
165	PMD(PMD_SX, ("!We woke up!\n"))
166
167	PT(PT_LSS);
168	if (AcpiLeaveSleepState(Sx) != AE_OK) {
169		PT(PT_LSS_FAIL);
170		PMD(PMD_SX, ("Problem with LeaveSleepState!\n"))
171	}
172
173	PT(PT_CPB);
174	if (AcpiClearEvent(ACPI_EVENT_POWER_BUTTON) != AE_OK) {
175		PT(PT_CPB_FAIL);
176		PMD(PMD_SX, ("Problem w/ ClearEvent(POWER_BUTTON)\n"))
177	}
178	if (acpi_rtc_wake > 0 &&
179	    AcpiDisableEvent(ACPI_EVENT_RTC, 0) != AE_OK) {
180		PT(PT_DRTC_FAIL);
181		PMD(PMD_SX, ("Problem w/ DisableEvent(RTC)\n"))
182	}
183
184	PMD(PMD_SX, ("Exiting acpi_sleepstate() => 0\n"))
185
186	return (0);
187}
188