+++ /dev/null
-/** @file\r
-File to contain all the hardware specific stuff for the Periodical Timer dispatch protocol.\r
-\r
-Copyright (c) 2013-2016 Intel Corporation.\r
-\r
-SPDX-License-Identifier: BSD-2-Clause-Patent\r
-\r
-\r
-**/\r
-\r
-//\r
-// Include common header file for this module.\r
-//\r
-#include "CommonHeader.h"\r
-\r
-#include "QNCSmmHelpers.h"\r
-\r
-typedef enum {\r
- PERIODIC_TIMER = 0,\r
- NUM_TIMERS\r
-} SUPPORTED_TIMER;\r
-\r
-typedef struct _TIMER_INTERVAL\r
-{\r
- UINT64 Interval;\r
- UINT8 AssociatedTimer;\r
-} TIMER_INTERVAL;\r
-\r
-//\r
-// Time constants, in 100 nano-second units\r
-//\r
-#define TIME_64s 640000000 /* 64 s */\r
-#define TIME_32s 320000000 /* 32 s */\r
-#define TIME_16s 160000000 /* 16 s */\r
-#define TIME_8s 80000000 /* 8 s */\r
-#define TIME_64ms 640000 /* 64 ms */\r
-#define TIME_32ms 320000 /* 32 ms */\r
-#define TIME_16ms 160000 /* 16 ms */\r
-#define TIME_1_5ms 15000 /* 1.5 ms */\r
-\r
-// PMCW (GPE+28h) [2:0] Periodic SMI Rate selection\r
-// 000 1.5ms\r
-// 001 16ms\r
-// 010 32ms\r
-// 011 64ms\r
-// 100 8s\r
-// 101 16s\r
-// 110 32s\r
-// 111 64s\r
-\r
-typedef enum {\r
- INDEX_TIME_1_5ms = 0,\r
- INDEX_TIME_16ms,\r
- INDEX_TIME_32ms,\r
- INDEX_TIME_64ms,\r
- INDEX_TIME_8s,\r
- INDEX_TIME_16s,\r
- INDEX_TIME_32s,\r
- INDEX_TIME_64s,\r
- INDEX_TIME_MAX\r
-} TIMER_INTERVAL_INDEX;\r
-\r
-TIMER_INTERVAL mSmmPeriodicTimerIntervals[INDEX_TIME_MAX] = {\r
- {TIME_1_5ms, PERIODIC_TIMER},\r
- {TIME_16ms, PERIODIC_TIMER},\r
- {TIME_32ms, PERIODIC_TIMER},\r
- {TIME_64ms, PERIODIC_TIMER},\r
- { TIME_8s, PERIODIC_TIMER },\r
- {TIME_16s, PERIODIC_TIMER},\r
- {TIME_32s, PERIODIC_TIMER},\r
- {TIME_64s, PERIODIC_TIMER}\r
-};\r
-\r
-typedef struct _TIMER_INFO {\r
- UINTN NumChildren; // number of children using this timer\r
- UINT64 MinReqInterval; // minimum interval required by children\r
- UINTN CurrentSetting; // interval this timer is set at right now (index into interval table)\r
-} TIMER_INFO;\r
-\r
-TIMER_INFO mTimers[NUM_TIMERS];\r
-\r
-QNC_SMM_SOURCE_DESC mTIMER_SOURCE_DESCS[NUM_TIMERS] = {\r
- {\r
- QNC_SMM_NO_FLAGS,\r
- {\r
- {{GPE_ADDR_TYPE, {R_QNC_GPE0BLK_SMIE}}, S_QNC_GPE0BLK_SMIE, N_QNC_GPE0BLK_SMIE_SWT},\r
- NULL_BIT_DESC_INITIALIZER\r
- },\r
- {\r
- {{GPE_ADDR_TYPE, {R_QNC_GPE0BLK_SMIS}}, S_QNC_GPE0BLK_SMIS, N_QNC_GPE0BLK_SMIS_SWT}\r
- }\r
- }\r
-};\r
-\r
-VOID\r
-QNCSmmPeriodicTimerProgramTimers(\r
- VOID\r
- );\r
-\r
-\r
-TIMER_INTERVAL *\r
-ContextToTimerInterval (\r
- IN QNC_SMM_CONTEXT *RegisterContext\r
- )\r
-{\r
- UINTN loopvar;\r
-\r
- //\r
- // Determine which timer this child is using\r
- //\r
- for (loopvar = 0; loopvar < INDEX_TIME_MAX; loopvar++) {\r
- if (((RegisterContext->PeriodicTimer.SmiTickInterval == 0) && (RegisterContext->PeriodicTimer.Period >= mSmmPeriodicTimerIntervals[loopvar].Interval)) ||\r
- (RegisterContext->PeriodicTimer.SmiTickInterval == mSmmPeriodicTimerIntervals[loopvar].Interval)\r
- ) {\r
- return &mSmmPeriodicTimerIntervals[loopvar];\r
- }\r
- }\r
-\r
- //\r
- // If this assertion fires, then either:\r
- // (1) the context contains an invalid interval\r
- // (2) the timer interval table is corrupt\r
- //\r
- // ASSERT (FALSE);\r
-\r
- return NULL;\r
-}\r
-\r
-EFI_STATUS\r
-MapPeriodicTimerToSrcDesc (\r
- IN QNC_SMM_CONTEXT *RegisterContext,\r
- OUT QNC_SMM_SOURCE_DESC *SrcDesc\r
- )\r
-{\r
- TIMER_INTERVAL *TimerInterval;\r
-\r
- //\r
- // Figure out which timer the child is requesting and\r
- // send back the source description\r
- //\r
- TimerInterval = ContextToTimerInterval (RegisterContext);\r
- if (TimerInterval == NULL) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
- CopyMem (SrcDesc, &mTIMER_SOURCE_DESCS[TimerInterval->AssociatedTimer], sizeof (QNC_SMM_SOURCE_DESC));;\r
-\r
- //\r
- // Program the value of the interval into hardware\r
- //\r
- QNCSmmPeriodicTimerProgramTimers ();\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-VOID\r
-PeriodicTimerGetContext (\r
- IN DATABASE_RECORD *Record,\r
- OUT QNC_SMM_CONTEXT *HwContext\r
- )\r
-{\r
- TIMER_INTERVAL *TimerInterval;\r
-\r
- ASSERT (Record->ProtocolType == PeriodicTimerType);\r
-\r
- TimerInterval = ContextToTimerInterval (&Record->ChildContext);\r
-\r
- if (TimerInterval != NULL) {\r
- //\r
- // Ignore the hardware context. It's not required for this protocol.\r
- // Instead, just increment the child's context.\r
- // Update the elapsed time w/ the data from our tables\r
- //\r
- Record->CommBuffer.PeriodicTimer.ElapsedTime += TimerInterval->Interval;\r
- CopyMem (HwContext, &Record->ChildContext, sizeof (QNC_SMM_CONTEXT));\r
- }\r
-}\r
-\r
-BOOLEAN\r
-PeriodicTimerCmpContext (\r
- IN QNC_SMM_CONTEXT *HwContext,\r
- IN QNC_SMM_CONTEXT *ChildContext\r
- )\r
-{\r
- DATABASE_RECORD *Record;\r
-\r
- Record = DATABASE_RECORD_FROM_CONTEXT (ChildContext);\r
-\r
- if (Record->CommBuffer.PeriodicTimer.ElapsedTime >= ChildContext->PeriodicTimer.Period) {\r
- //\r
- // This child should be dispatched\r
- // The timer will be restarted on the "ClearSource" call.\r
- //\r
- return TRUE;\r
- } else {\r
- return FALSE;\r
- }\r
-}\r
-\r
-VOID\r
-PeriodicTimerGetBuffer (\r
- IN DATABASE_RECORD * Record\r
- )\r
-{\r
- //\r
- // CommBuffer has been updated by PeriodicTimerGetContext, so return directly\r
- //\r
- return;\r
-}\r
-\r
-VOID\r
-QNCSmmPeriodicTimerProgramTimers (\r
- VOID\r
- )\r
-{\r
- UINT32 GpePmcwValue;\r
- SUPPORTED_TIMER Timer;\r
- DATABASE_RECORD *RecordInDb;\r
- LIST_ENTRY *LinkInDb;\r
- TIMER_INTERVAL *TimerInterval;\r
-\r
- //\r
- // Find the minimum required interval for each timer\r
- //\r
- for (Timer = (SUPPORTED_TIMER)0; Timer < NUM_TIMERS; Timer++) {\r
- mTimers[Timer].MinReqInterval = ~(UINT64)0x0;\r
- mTimers[Timer].NumChildren = 0;\r
- }\r
- LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase);\r
- while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) {\r
- RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb);\r
- if (RecordInDb->ProtocolType == PeriodicTimerType) {\r
- //\r
- // This child is registerd with the PeriodicTimer protocol\r
- //\r
- TimerInterval = ContextToTimerInterval (&RecordInDb->ChildContext);\r
-\r
- if(TimerInterval != NULL) {\r
- Timer = (SUPPORTED_TIMER)((TIMER_INTERVAL *) (TimerInterval))->AssociatedTimer;\r
-\r
- ASSERT (Timer >= 0 && Timer < NUM_TIMERS);\r
-\r
- if (mTimers[Timer].MinReqInterval > RecordInDb->ChildContext.PeriodicTimer.SmiTickInterval) {\r
- mTimers[Timer].MinReqInterval = RecordInDb->ChildContext.PeriodicTimer.SmiTickInterval;\r
- }\r
- mTimers[Timer].NumChildren++;\r
- }\r
- }\r
- LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, &RecordInDb->Link);\r
- }\r
-\r
- //\r
- // Program the hardware\r
- //\r
- GpePmcwValue = 0;\r
- if (mTimers[PERIODIC_TIMER].NumChildren > 0) {\r
- switch (mTimers[PERIODIC_TIMER].MinReqInterval) {\r
-\r
- case TIME_64s:\r
- GpePmcwValue = INDEX_TIME_64s;\r
- mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_64s;\r
- break;\r
-\r
- case TIME_32s:\r
- GpePmcwValue = INDEX_TIME_32s;\r
- mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_32s;\r
- break;\r
-\r
- case TIME_16s:\r
- GpePmcwValue = INDEX_TIME_16s;\r
- mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_16s;\r
- break;\r
-\r
- case TIME_8s:\r
- GpePmcwValue = INDEX_TIME_8s;\r
- mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_8s;\r
- break;\r
-\r
- case TIME_64ms:\r
- GpePmcwValue = INDEX_TIME_64ms;\r
- mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_64ms;\r
- break;\r
-\r
- case TIME_32ms:\r
- GpePmcwValue = INDEX_TIME_32ms;\r
- mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_32ms;\r
- break;\r
-\r
- case TIME_16ms:\r
- GpePmcwValue = INDEX_TIME_16ms;\r
- mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_16ms;\r
- break;\r
-\r
- case TIME_1_5ms:\r
- GpePmcwValue = INDEX_TIME_1_5ms;\r
- mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_1_5ms;\r
- break;\r
-\r
- default:\r
- ASSERT (FALSE);\r
- break;\r
- };\r
-\r
- GpePmcwValue |= B_QNC_GPE0BLK_PMCW_PSE;\r
-\r
- IoOr32(((UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_PMCW), GpePmcwValue);\r
-\r
- //\r
- // Restart the timer here, just need to clear the SMI\r
- //\r
- QNCSmmClearSource (&mTIMER_SOURCE_DESCS[PERIODIC_TIMER]);\r
- } else {\r
- QNCSmmDisableSource (&mTIMER_SOURCE_DESCS[PERIODIC_TIMER]);\r
- }\r
-}\r
-\r
-EFI_STATUS\r
-QNCSmmPeriodicTimerDispatchGetNextShorterInterval (\r
- IN CONST EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL *This,\r
- IN OUT UINT64 **SmiTickInterval\r
- )\r
-/*++\r
-\r
-Routine Description:\r
-\r
- This services returns the next SMI tick period that is supported by the chipset.\r
- The order returned is from longest to shortest interval period.\r
-\r
-Arguments:\r
-\r
- This - Pointer to the EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL instance.\r
- SmiTickInterval - Pointer to pointer of the next shorter SMI interval period that is supported by the child.\r
-\r
-Returns:\r
-\r
- EFI_SUCCESS - The service returned successfully.\r
- EFI_INVALID_PARAMETER - The parameter SmiTickInterval is invalid.\r
-\r
---*/\r
-{\r
- TIMER_INTERVAL *IntervalPointer;\r
-\r
- ASSERT (SmiTickInterval != NULL);\r
-\r
- IntervalPointer = (TIMER_INTERVAL*)*SmiTickInterval;\r
-\r
- if (IntervalPointer == NULL) {\r
- //\r
- // The first time child requesting an interval\r
- //\r
- IntervalPointer = &mSmmPeriodicTimerIntervals[0];\r
- } else if (IntervalPointer == &mSmmPeriodicTimerIntervals[INDEX_TIME_MAX - 1]) {\r
- //\r
- // At end of the list\r
- //\r
- IntervalPointer = NULL;\r
- } else {\r
- if ((IntervalPointer >= &mSmmPeriodicTimerIntervals[0]) &&\r
- (IntervalPointer < &mSmmPeriodicTimerIntervals[INDEX_TIME_MAX - 1])) {\r
- //\r
- // Get the next interval in the list\r
- //\r
- IntervalPointer++;\r
- } else {\r
- //\r
- // Input is out of range\r
- //\r
- return EFI_INVALID_PARAMETER;\r
- }\r
- }\r
-\r
- if (IntervalPointer != NULL) {\r
- *SmiTickInterval = &IntervalPointer->Interval;\r
- } else {\r
- *SmiTickInterval = NULL;\r
- }\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-VOID\r
-QNCSmmPeriodicTimerClearSource (\r
- IN QNC_SMM_SOURCE_DESC *SrcDesc\r
- )\r
-/*++\r
-\r
-Routine Description:\r
-\r
- This function is responsible for calculating and enabling any timers that are required\r
- to dispatch messages to children. The SrcDesc argument isn't acutally used.\r
-\r
-Arguments:\r
-\r
- SrcDesc - Pointer to the QNC_SMM_SOURCE_DESC instance.\r
-\r
-Returns:\r
-\r
- None.\r
-\r
---*/\r
-{\r
- DATABASE_RECORD *RecordInDb;\r
- LIST_ENTRY *LinkInDb;\r
-\r
- QNCSmmPeriodicTimerProgramTimers ();\r
-\r
- //\r
- // Reset Elapsed time\r
- //\r
- LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase);\r
- while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) {\r
- RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb);\r
- if (RecordInDb->ProtocolType == PeriodicTimerType) {\r
- //\r
- // This child is registerd with the PeriodicTimer protocol and Callback\r
- // has been invoked, so reset the ElapsedTime to 0\r
- //\r
- if (RecordInDb->CommBuffer.PeriodicTimer.ElapsedTime >= RecordInDb->ChildContext.PeriodicTimer.Period) {\r
- RecordInDb->CommBuffer.PeriodicTimer.ElapsedTime = 0;\r
- }\r
- }\r
- LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, &RecordInDb->Link);\r
- }\r
-}\r
-\r