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 
  57 int acpi_rtc_wake = 0x0;                /* wake in N seconds */
  58 
  59 #if 0   /* debug */
  60 static uint8_t  branchbuf[64 * 1024];   /* for the HDT branch trace stuff */
  61 #endif  /* debug */
  62 
  63 extern int boothowto;
  64 
  65 #define BOOTCPU 0       /* cpu 0 is always the boot cpu */
  66 
  67 extern void             kernel_wc_code(void);
  68 extern tod_ops_t        *tod_ops;
  69 extern int flushes_require_xcalls;
  70 extern int tsc_gethrtime_enable;
  71 
  72 extern cpuset_t cpu_ready_set;
  73 
  74 
  75 /*
  76  * This is what we've all been waiting for!
  77  */
  78 int
  79 acpi_enter_sleepstate(s3a_t *s3ap)
  80 {
  81         ACPI_PHYSICAL_ADDRESS   wakephys = s3ap->s3a_wakephys;
  82         caddr_t                 wakevirt = rm_platter_va;
  83         /*LINTED*/
  84         wakecode_t              *wp = (wakecode_t *)wakevirt;
  85         uint_t                  Sx = s3ap->s3a_state;
  86 
  87         PT(PT_SWV);
  88         /* Set waking vector */
  89         if (AcpiSetFirmwareWakingVector(wakephys) != AE_OK) {
  90                 PT(PT_SWV_FAIL);
  91                 PMD(PMD_SX, ("Can't SetFirmwareWakingVector(%lx)\n",
  92                     (long)wakephys))
  93                 goto insomnia;
  94         }
  95 
  96         PT(PT_EWE);
  97         /* Enable wake events */
  98         if (AcpiEnableEvent(ACPI_EVENT_POWER_BUTTON, 0) != AE_OK) {
  99                 PT(PT_EWE_FAIL);
 100                 PMD(PMD_SX, ("Can't EnableEvent(POWER_BUTTON)\n"))
 101         }
 102         if (acpi_rtc_wake > 0) {
 103                 /* clear the RTC bit first */
 104                 (void) AcpiWriteBitRegister(ACPI_BITREG_RT_CLOCK_STATUS, 1);
 105                 PT(PT_RTCW);
 106                 if (AcpiEnableEvent(ACPI_EVENT_RTC, 0) != AE_OK) {
 107                         PT(PT_RTCW_FAIL);
 108                         PMD(PMD_SX, ("Can't EnableEvent(RTC)\n"))
 109                 }
 110 
 111                 /*
 112                  * Set RTC to wake us in a wee while.
 113                  */
 114                 mutex_enter(&tod_lock);
 115                 PT(PT_TOD);
 116                 TODOP_SETWAKE(tod_ops, acpi_rtc_wake);
 117                 mutex_exit(&tod_lock);
 118         }
 119 
 120         /*
 121          * Prepare for sleep ... could've done this earlier?
 122          */
 123         PT(PT_SXP);
 124         PMD(PMD_SX, ("Calling AcpiEnterSleepStatePrep(%d) ...\n", Sx))
 125         if (AcpiEnterSleepStatePrep(Sx) != AE_OK) {
 126                 PMD(PMD_SX, ("... failed\n!"))
 127                 goto insomnia;
 128         }
 129 
 130         switch (s3ap->s3a_test_point) {
 131         case DEVICE_SUSPEND_TO_RAM:
 132         case FORCE_SUSPEND_TO_RAM:
 133         case LOOP_BACK_PASS:
 134                 return (0);
 135         case LOOP_BACK_FAIL:
 136                 return (1);
 137         default:
 138                 ASSERT(s3ap->s3a_test_point == LOOP_BACK_NONE);
 139         }
 140 
 141         /*
 142          * Tell the hardware to sleep.
 143          */
 144         PT(PT_SXE);
 145         PMD(PMD_SX, ("Calling AcpiEnterSleepState(%d) ...\n", Sx))
 146         if (AcpiEnterSleepState(Sx) != AE_OK) {
 147                 PT(PT_SXE_FAIL);
 148                 PMD(PMD_SX, ("... failed!\n"))
 149         }
 150 
 151 insomnia:
 152         PT(PT_INSOM);
 153         /* cleanup is done in the caller */
 154         return (1);
 155 }
 156 
 157 int
 158 acpi_exit_sleepstate(s3a_t *s3ap)
 159 {
 160         int Sx = s3ap->s3a_state;
 161 
 162         PT(PT_WOKE);
 163         PMD(PMD_SX, ("!We woke up!\n"))
 164 
 165         PT(PT_LSS);
 166         if (AcpiLeaveSleepState(Sx) != AE_OK) {
 167                 PT(PT_LSS_FAIL);
 168                 PMD(PMD_SX, ("Problem with LeaveSleepState!\n"))
 169         }
 170 
 171         PT(PT_CPB);
 172         if (AcpiClearEvent(ACPI_EVENT_POWER_BUTTON) != AE_OK) {
 173                 PT(PT_CPB_FAIL);
 174                 PMD(PMD_SX, ("Problem w/ ClearEvent(POWER_BUTTON)\n"))
 175         }
 176         if (acpi_rtc_wake > 0 &&
 177             AcpiDisableEvent(ACPI_EVENT_RTC, 0) != AE_OK) {
 178                 PT(PT_DRTC_FAIL);
 179                 PMD(PMD_SX, ("Problem w/ DisableEvent(RTC)\n"))
 180         }
 181 
 182         PMD(PMD_SX, ("Exiting acpi_sleepstate() => 0\n"))
 183 
 184         return (0);
 185 }