use pushfl/popfl with gcc to fix the 32bit build
[AROS.git] / arch / all-pc / kernel / acpi_pm.c
bloba7260d857623cdbb43b596c07d125656665e1698
1 /*
2 Copyright © 2017, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 #include <aros/asmcall.h>
7 #include <proto/acpica.h>
8 #include <proto/exec.h>
10 #include <acpica/acnames.h>
11 #include <acpica/accommon.h>
13 #include "kernel_base.h"
14 #include "kernel_debug.h"
15 #include "kernel_globals.h"
16 #include "kernel_intern.h"
18 #include "acpi.h"
20 #define D(x)
22 #define ACPI_MODPRIO_PM 10
24 /************************************************************************************************
25 ACPI PM RELATED FUNCTIONS
26 ************************************************************************************************/
28 const char *ACPI_TABLE_FADT_STR __attribute__((weak)) = ACPI_SIG_FADT;
30 /* Deafult ACPI PM Syscall Handlers */
32 void ACPI_HandleChangePMStateSC(struct ExceptionContext *regs)
34 struct KernelBase *KernelBase = getKernelBase();
35 struct ACPIData *acpiData = KernelBase->kb_PlatformData->kb_ACPI;
37 UBYTE pmState =
38 #if (__WORDSIZE==64)
39 (UBYTE)regs->rbx;
40 #else
41 (UBYTE)regs->ebx;
42 #endif
44 D(bug("[Kernel:ACPI-PM] %s(0x%02x)\n", __func__, pmState));
46 if (pmState == 0xFF)
48 ACPI_GENERIC_ADDRESS tmpReg;
49 ACPI_TABLE_FADT *fadt = (ACPI_TABLE_FADT *)acpiData->acpi_fadt;
51 D(bug("[Kernel:ACPI-PM] %s: STATE 0xFF - Cold Rebooting...\n", __func__));
52 D(bug("[Kernel:ACPI-PM] %s: FADT Reset Register @ 0x%p, Width %d, Offset %d, MemSpace %d\n", __func__, (IPTR)fadt->ResetRegister.Address, fadt->ResetRegister.BitWidth, fadt->ResetRegister.BitOffset, fadt->ResetRegister.SpaceId));
53 D(bug("[Kernel:ACPI-PM] %s: FADT Reset Value = 0x%2x\n", __func__, fadt->ResetValue));
55 AcpiWrite (fadt->ResetValue, &fadt->ResetRegister);
57 // If we got here the reset didnt happen,
58 // check if we are the known "faulty" implementation.
60 if ((fadt->Header.Revision >= 2) &&
61 (fadt->ResetRegister.Address == 0xCF9))
63 D(bug("[Kernel:ACPI-PM] %s: Failed Reset? Using workaround...\n", __func__));
64 tmpReg.Address = 0x64;
65 tmpReg.BitWidth = fadt->ResetRegister.BitWidth;
66 tmpReg.BitOffset = fadt->ResetRegister.BitOffset;
67 tmpReg.SpaceId = fadt->ResetRegister.SpaceId;
69 AcpiWrite (0xFE, &tmpReg);
71 bug("[Kernel:ACPI-PM] %s: Reset Failed.\n", __func__);
73 else if (pmState == 0)
75 ACPI_STATUS status;
76 ACPI_OBJECT arg = { ACPI_TYPE_INTEGER };
77 ACPI_OBJECT_LIST arg_list = { 1, &arg };
78 char *pathName;
79 UINT8 acpiSleepTypeA, acpiSleepTypeB;
80 ACPI_TABLE_FADT *fadt = (ACPI_TABLE_FADT *)acpiData->acpi_fadt;
82 D(bug("[Kernel:ACPI-PM] %s: STATE 0x00 - Powering Off...\n", __func__));
84 // we must be in user-mode with interrupts enabled to use AcpiCA
85 krnLeaveSupervisorRing(FLAGS_INTENABLED);
87 status = AcpiGetSleepTypeData(ACPI_STATE_S5,
88 &acpiSleepTypeA, &acpiSleepTypeB);
90 if (!ACPI_FAILURE(status))
92 D(bug("[Kernel:ACPI-PM] %s: %d:%d\n", __func__, acpiSleepTypeA, acpiSleepTypeB));
94 // call Prepare To Sleep
95 arg.Integer.Value = ACPI_STATE_S5;
96 pathName = METHOD_PATHNAME__PTS;
97 D(bug("[Kernel:ACPI-PM] %s: > ACPI %s\n", __func__, &pathName[1]));
98 status = AcpiEvaluateObject(NULL,
99 pathName,
100 &arg_list,
101 NULL);
103 else
105 pathName = (char *)" ACPI Sleep Type Data";
108 if (!ACPI_FAILURE(status) || (status == AE_NOT_FOUND))
110 // call System State Transition...
111 // n.b: this is an optional method so we
112 // ignore the return value
113 arg.Integer.Value = ACPI_SST_INDICATOR_OFF;
114 pathName = METHOD_PATHNAME__SST;
115 D(bug("[Kernel:ACPI-PM] %s: > ACPI %s\n", __func__, &pathName[1]));
116 status = AcpiEvaluateObject(NULL,
117 pathName,
118 &arg_list,
119 NULL);
120 status = AE_OK;
123 if (!ACPI_FAILURE(status))
125 if (fadt->Flags & ACPI_FADT_HW_REDUCED)
127 pathName = (char *)" ACPI Sleep Control";
128 if (!fadt->SleepControl.Address ||
129 !fadt->SleepStatus.Address)
131 status = AE_NOT_EXIST;
133 else
135 acpiSleepTypeB = ((acpiSleepTypeA << ACPI_X_SLEEP_TYPE_POSITION) & ACPI_X_SLEEP_TYPE_MASK);
137 D(bug("[Kernel:ACPI-PM] %s: Sleep Control Register @ 0x%p, Width %d, Offset %d, MemSpace %d\n", __func__, (IPTR)fadt->SleepControl.Address, fadt->SleepControl.BitWidth, fadt->SleepControl.BitOffset, fadt->SleepControl.SpaceId));
138 D(bug("[Kernel:ACPI-PM] %s: Sleep Value = 0x%2x\n", __func__, acpiSleepTypeB));
140 status = AcpiWrite ((UINT64) (acpiSleepTypeB | ACPI_X_SLEEP_ENABLE), &fadt->SleepControl);
143 else
145 ACPI_BIT_REGISTER_INFO *sleepTypeRegInfo;
146 ACPI_BIT_REGISTER_INFO *sleepEnableRegInfo;
147 UINT32 xpm1aControl, xpm1bControl;
149 sleepTypeRegInfo = AcpiHwGetBitRegisterInfo (ACPI_BITREG_SLEEP_TYPE);
150 sleepEnableRegInfo = AcpiHwGetBitRegisterInfo (ACPI_BITREG_SLEEP_ENABLE);
152 // Clear ACPI Wake status */
153 pathName = " ACPI Wake Status";
154 status = AcpiWriteBitRegister (ACPI_BITREG_WAKE_STATUS, ACPI_CLEAR_STATUS);
156 // Read the PM1A control value
157 if (!ACPI_FAILURE (status))
159 pathName = " PM1A Control Value";
160 status = AcpiReadBitRegister (ACPI_REGISTER_PM1_CONTROL, &xpm1aControl);
163 // First, write only SLP_TYP to PM1
164 if (!ACPI_FAILURE (status))
166 pathName = " PM1 SLP_TYP";
167 xpm1aControl &= ~(sleepTypeRegInfo->AccessBitMask |
168 sleepEnableRegInfo->AccessBitMask);
169 xpm1bControl = xpm1aControl;
171 xpm1aControl |= (acpiSleepTypeA << sleepTypeRegInfo->BitPosition);
172 xpm1bControl |= (acpiSleepTypeB << sleepTypeRegInfo->BitPosition);
174 D(bug("[Kernel:ACPI-PM] %s: PM1A = 0xd\n", __func__, xpm1aControl));
176 status = AcpiWrite (xpm1aControl, &fadt->XPm1aControlBlock);
179 if ((!ACPI_FAILURE (status)) && (fadt->XPm1bControlBlock.Address))
181 status = AcpiWrite (xpm1bControl, &fadt->XPm1bControlBlock);
184 // Second, write both SLP_TYP and SLP_EN to PM1
185 if (!ACPI_FAILURE (status))
187 pathName = " PM1 SLP_TYP|SLP_EN";
188 xpm1aControl |= sleepEnableRegInfo->AccessBitMask;
189 xpm1bControl |= sleepEnableRegInfo->AccessBitMask;
191 D(bug("[Kernel:ACPI-PM] %s: PM1A = 0xd\n", __func__, xpm1aControl));
193 CacheClearU();
195 status = AcpiWrite (xpm1aControl, &fadt->XPm1aControlBlock);
198 if ((!ACPI_FAILURE (status)) && (fadt->XPm1bControlBlock.Address))
200 status = AcpiWrite (xpm1bControl, &fadt->XPm1bControlBlock);
205 if (ACPI_FAILURE(status))
207 bug("[Kernel:ACPI-PM] %s: Error evaluating %s: %s\n", __func__, &pathName[1], AcpiFormatException(status));
210 else if (pmState == 0x90)
212 #if defined(__AROSEXEC_SMP__)
213 UQUAD timeSleep = RDTSC();
214 UQUAD timeWake;
215 struct APICData *apicData = KernelBase->kb_PlatformData->kb_APIC;
216 apicid_t cpunum = core_APIC_GetNumber(apicData);
217 #endif
218 #if (__WORDSIZE==64)
219 asm volatile ("pushfq; sti; hlt; popfq");
220 #else
221 asm volatile ("pushfl; sti; hlt; popfl");
222 #endif
223 #if defined(__AROSEXEC_SMP__)
224 timeWake = RDTSC();
225 apicData->cores[cpunum].cpu_SleepTime += timeWake - timeSleep;
226 #endif
228 else
230 // We cant handle any other states atm =/
231 D(bug("[Kernel:ACPI-PM] %s: UNHANDLED STATE 0x%02x\n", __func__, pmState));
235 struct syscallx86_Handler ACPI_SCChangePMStateHandler =
238 .ln_Name = (APTR)SC_X86CHANGEPMSTATE
240 (APTR)ACPI_HandleChangePMStateSC
244 * Process the FADT Table
246 AROS_UFH3(static IPTR, ACPI_hook_Table_PM_Probe,
247 AROS_UFHA(struct Hook *, table_hook, A0),
248 AROS_UFHA(ACPI_TABLE_FADT *, fadt, A2),
249 AROS_UFHA(struct ACPI_TABLESCAN_DATA *, tsdata, A1))
251 AROS_USERFUNC_INIT
253 struct PlatformData *pdata = tsdata->acpits_UserData;
255 D(bug("[Kernel:ACPI-IOAPIC] ## %s()\n", __func__));
257 // cache the FADT pointer ...
258 pdata->kb_ACPI->acpi_fadt = fadt;
260 if (fadt->Flags & ACPI_FADT_RESET_REGISTER)
262 // register the ACPI ChangePMState SysCall Handler ..
263 krnAddSysCallHandler(pdata, &ACPI_SCChangePMStateHandler, TRUE, FALSE);
266 return TRUE;
268 AROS_USERFUNC_EXIT
272 void ACPI_PM_SUPPORT(struct PlatformData *pdata)
274 struct ACPI_TABLE_HOOK *scanHook;
276 scanHook = (struct ACPI_TABLE_HOOK *)AllocMem(sizeof(struct ACPI_TABLE_HOOK), MEMF_CLEAR);
277 if (scanHook)
279 D(bug("[Kernel:ACPI-PM] %s: Registering PM Table Parser...\n", __func__));
280 D(bug("[Kernel:ACPI-PM] %s: Table Hook @ 0x%p\n", __func__, scanHook));
281 scanHook->acpith_Node.ln_Name = (char *)ACPI_TABLE_FADT_STR;
282 scanHook->acpith_Node.ln_Pri = ACPI_MODPRIO_PM;
283 scanHook->acpith_Hook.h_Entry = (APTR)ACPI_hook_Table_PM_Probe;
284 scanHook->acpith_HeaderLen = 0;
285 scanHook->acpith_EntryType = 0;
286 scanHook->acpith_UserData = pdata;
287 Enqueue(&pdata->kb_ACPI->acpi_tablehooks, &scanHook->acpith_Node);
289 D(bug("[Kernel:ACPI-PM] %s: Registering done\n", __func__));
292 DECLARESET(KERNEL__ACPISUPPORT)
293 ADD2SET(ACPI_PM_SUPPORT, KERNEL__ACPISUPPORT, 0)