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 extern void *(*cpu_pause_func)(void *);
  74 
  75 
  76 
  77 /*
  78  * This is what we've all been waiting for!
  79  */
  80 int
  81 acpi_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 
 153 insomnia:
 154         PT(PT_INSOM);
 155         /* cleanup is done in the caller */
 156         return (1);
 157 }
 158 
 159 int
 160 acpi_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 }