/** @file IPMI FRB Driver. Copyright (c) 2018, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License that accompanies this distribution. The full text of the license may be found at http://opensource.org/licenses/bsd-license.php. THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. **/ #include #include #include #include #include #include #include #include #include #include EFI_STATUS EfiDisableFrb ( VOID ) /*++ Routine Description: This routine disables the specified FRB timer. Arguments: This - This pointer FrbType - Type of FRB timer to get data on Returns: EFI_SUCCESS - FRB timer was disabled EFI_ABORTED - Timer was already stopped EFI_UNSUPPORTED - This type of FRB timer is not supported. --*/ { EFI_STATUS Status; IPMI_SET_WATCHDOG_TIMER_REQUEST SetWatchdogTimer; UINT8 CompletionCode; IPMI_GET_WATCHDOG_TIMER_RESPONSE GetWatchdogTimer; Status = IpmiGetWatchdogTimer (&GetWatchdogTimer); if (EFI_ERROR (Status)) { return Status; } // // Check if timer is still running, if not abort disable routine. // if (GetWatchdogTimer.TimerUse.TimerRunning == 0) { return EFI_ABORTED; } ZeroMem (&SetWatchdogTimer, sizeof(SetWatchdogTimer)); // // Just flip the Timer Use bit. This should release the timer. // SetWatchdogTimer.TimerUse.TimerRunning = 0; SetWatchdogTimer.TimerUse.TimerUse = IPMI_WATCHDOG_TIMER_BIOS_FRB2; SetWatchdogTimer.TimerUseExpirationFlagsClear &= ~BIT2; SetWatchdogTimer.TimerUseExpirationFlagsClear |= BIT1 | BIT4; Status = IpmiSetWatchdogTimer (&SetWatchdogTimer, &CompletionCode); return Status; } VOID EFIAPI DisableFRB2Handler ( IN EFI_EVENT Event, IN VOID *Context ) /*++ Routine Description: Disables FRB2. This function gets called each time the EFI_EVENT_SIGNAL_READY_TO_BOOT gets signaled Arguments: Standard event notification function arguments: Event - the event that is signaled. Context - not used here. Returns: --*/ { DEBUG((EFI_D_ERROR, "!!! enter DisableFRB2Handler()!!!\n")); EfiDisableFrb (); } EFI_STATUS CheckForAndReportErrors( VOID ) /*++ Routine Description: Check the Watchdog timer expiration flags and report the kind of watchdog timeout occurred to the Error Manager. Arguments: Returns: EFI_SUCCESS - Errors retrieved and reported --*/ { EFI_STATUS Status; IPMI_GET_WATCHDOG_TIMER_RESPONSE GetWatchdogTimer; IPMI_SET_WATCHDOG_TIMER_REQUEST SetWatchdogTimer; UINT8 CompletionCode; // // Get the Watchdog timer info to find out what kind of timer expiration occurred. // Status = IpmiGetWatchdogTimer (&GetWatchdogTimer); if (EFI_ERROR (Status)) { return Status; } // // If FRB2 Failure occurred, report it to the error manager and log a SEL. // if ((GetWatchdogTimer.TimerUseExpirationFlagsClear & BIT1) != 0) { // // Report the FRB2 time-out error // } else if ((GetWatchdogTimer.TimerUseExpirationFlagsClear & BIT3) != 0) { // // Report the OS Watchdog timer failure // } // // Need to clear Timer expiration flags after checking. // ZeroMem (&SetWatchdogTimer, sizeof(SetWatchdogTimer)); SetWatchdogTimer.TimerUse = GetWatchdogTimer.TimerUse; SetWatchdogTimer.TimerActions = GetWatchdogTimer.TimerActions; SetWatchdogTimer.PretimeoutInterval = GetWatchdogTimer.PretimeoutInterval; SetWatchdogTimer.TimerUseExpirationFlagsClear = GetWatchdogTimer.TimerUseExpirationFlagsClear; SetWatchdogTimer.InitialCountdownValue = GetWatchdogTimer.InitialCountdownValue; SetWatchdogTimer.TimerUse.TimerRunning = 1; SetWatchdogTimer.TimerUseExpirationFlagsClear |= BIT1 | BIT2 | BIT3; Status = IpmiSetWatchdogTimer (&SetWatchdogTimer, &CompletionCode); return Status; } EFI_STATUS ReportFrb2Status ( VOID ) /*++ Routine Description: This routine is built only when DEBUG_MODE is enabled. It is used to report the status of FRB2 when the FRB2 driver is installed. Arguments: none Returns: EFI_SUCCESS: All info was retrieved and reported EFI_ERROR: There was an error during info retrieval --*/ { EFI_STATUS Status; IPMI_GET_WATCHDOG_TIMER_RESPONSE GetWatchdogTimer; // // Get the Watchdog timer info to find out what kind of timer expiration occurred. // Status = IpmiGetWatchdogTimer (&GetWatchdogTimer); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_INFO, "Failed to get Watchdog Timer info from BMC.\n")); return Status; } // // Check if timer is running, report status to DEBUG_MODE output. // if (GetWatchdogTimer.TimerUse.TimerRunning == 1) { DEBUG ((DEBUG_INFO, "FRB2 Timer is running.\n")); } else { DEBUG ((DEBUG_INFO, "FRB2 Timer is not running.\n")); } return EFI_SUCCESS; } EFI_STATUS EFIAPI FrbDxeEntryPoint ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) /*++ Routine Description: This is the standard EFI driver point. This function intitializes the private data required for creating FRB Driver. Arguments: ImageHandle - Handle for the image of this driver SystemTable - Pointer to the EFI System Table Returns: EFI_SUCCESS - Protocol successfully started and installed EFI_UNSUPPORTED - Protocol can't be started --*/ { EFI_EVENT ReadyToBootEvent; EFI_STATUS Status; CheckForAndReportErrors(); ReportFrb2Status (); // // Register the event to Disable FRB2 before Boot. // Status = EfiCreateEventReadyToBootEx ( TPL_NOTIFY, DisableFRB2Handler, NULL, &ReadyToBootEvent ); return Status; }