diff options
Diffstat (limited to 'ReferenceCode/Chipset/LynxPoint/Smbus/Pei/PchSmbusArpEnabled.c')
-rw-r--r-- | ReferenceCode/Chipset/LynxPoint/Smbus/Pei/PchSmbusArpEnabled.c | 291 |
1 files changed, 291 insertions, 0 deletions
diff --git a/ReferenceCode/Chipset/LynxPoint/Smbus/Pei/PchSmbusArpEnabled.c b/ReferenceCode/Chipset/LynxPoint/Smbus/Pei/PchSmbusArpEnabled.c new file mode 100644 index 0000000..91a8614 --- /dev/null +++ b/ReferenceCode/Chipset/LynxPoint/Smbus/Pei/PchSmbusArpEnabled.c @@ -0,0 +1,291 @@ +/** @file + PCH Smbus PEIM. This file is used when we want ARP support. + +@copyright + Copyright (c) 2009 - 2012 Intel Corporation. All rights reserved + This software and associated documentation (if any) is furnished + under a license and may only be used or copied in accordance + with the terms of the license. Except as permitted by such + license, no part of this software or documentation may be + reproduced, stored in a retrieval system, or transmitted in any + form or by any means without the express written consent of + Intel Corporation. + + This file contains an 'Intel Peripheral Driver' and uniquely + identified as "Intel Reference Module" and is + licensed for Intel CPUs and chipsets under the terms of your + license agreement with Intel or your vendor. This file may + be modified by the user, subject to additional terms of the + license agreement + +**/ +#include "PchSmbus.h" + +static EFI_PEI_NOTIFY_DESCRIPTOR mNotifyList = { + (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), + &gEndOfPeiSignalPpiGuid, + EndOfPeiCallback +}; + +EFI_GUID mEfiSmbusArpMapGuid = EFI_SMBUS_ARP_MAP_GUID; + +/** + Set Slave address for an Smbus device with a known UDID or perform a general + ARP of all devices. + + @param[in] PeiServices Pointer to the PEI Services table. + @param[in] This Pointer to the instance of the PEI_SMBUS_PPI. + @param[in] ArpAll If TRUE, do a full ARP. Otherwise, just ARP the specified UDID. + @param[in] SmbusUdid When doing a directed ARP, ARP the device with this UDID. + @param[in, out] SlaveAddress Buffer to store new Slave Address during directed ARP. + + @exception EFI_UNSUPPORTED This functionality is not supported + @retval EFI_SUCCESS The function completed successfully. +**/ +EFI_STATUS +EFIAPI +SmbusArpDevice ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_SMBUS_PPI * This, + IN BOOLEAN ArpAll, + IN EFI_SMBUS_UDID * SmbusUdid OPTIONAL, + IN OUT EFI_SMBUS_DEVICE_ADDRESS * SlaveAddress OPTIONAL + ) +{ + SMBUS_INSTANCE *Private; + EFI_STATUS Status; + UINT8 OldMapEntries; + + DEBUG ((EFI_D_INFO, "PEI SmbusArpDevice() Start\n")); + + Private = SMBUS_PRIVATE_DATA_FROM_PPI_THIS (This); + + OldMapEntries = Private->DeviceMapEntries; + + if (ArpAll) { + Status = SmbusFullArp (Private); + } else { + if ((SmbusUdid == NULL) || (SlaveAddress == NULL)) { + return EFI_INVALID_PARAMETER; + } + + Status = SmbusDirectedArp (Private, SmbusUdid, SlaveAddress); + } + + if (EFI_ERROR (Status)) { + return Status; + } + /// + /// If we just added the first entry in the device map, set up a callback so + /// we can pass the map to DXE via a HOB at the end of PEI. + /// + if ((OldMapEntries == 0) && (Private->DeviceMapEntries > 0)) { + Status = (**PeiServices).NotifyPpi (PeiServices, &mNotifyList); + ASSERT_EFI_ERROR (Status); + } + + DEBUG ((EFI_D_INFO, "PEI SmbusArpDevice() End\n")); + + return EFI_SUCCESS; +} + +/** + Get a pointer to the assigned mappings of UDID's to Slave Addresses. + + @param[in] PeiServices Pointer to the PEI Services table. + @param[in] This Pointer to the instance of the PEI_SMBUS_PPI. + @param[in, out] Length Buffer to contain the lenght of the Device Map. + @param[in, out] SmbusDeviceMap Buffer to contian a pointer to the Device Map. + + @exception EFI_UNSUPPORTED This functionality is not supported + @retval EFI_SUCCESS The function completed successfully. +**/ +EFI_STATUS +EFIAPI +SmbusGetArpMap ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_SMBUS_PPI *This, + IN OUT UINTN *Length, + IN OUT EFI_SMBUS_DEVICE_MAP **SmbusDeviceMap + ) +{ + SMBUS_INSTANCE *Private; + + Private = SMBUS_PRIVATE_DATA_FROM_PPI_THIS (This); + + *Length = Private->DeviceMapEntries * sizeof (EFI_SMBUS_DEVICE_MAP); + *SmbusDeviceMap = Private->DeviceMap; + return EFI_SUCCESS; +} + +/** + Register a callback in the event of a Host Notify command being sent by a + specified Slave Device. + + @param[in] PeiServices The general PEI Services + @param[in] This The PPI instance + @param[in] SlaveAddress Address of the device whose Host Notify command we want to trap. + @param[in] Data Data of the Host Notify command we want to trap. + @param[in] NotifyFunction Function to be called in the event the desired Host Notify command occurs. + + @exception EFI_UNSUPPORTED This functionality is not supported + @retval EFI_SUCCESS The function completed successfully. +**/ +EFI_STATUS +EFIAPI +SmbusNotify ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_SMBUS_PPI *This, + IN EFI_SMBUS_DEVICE_ADDRESS SlaveAddress, + IN UINTN Data, + IN EFI_PEI_SMBUS_NOTIFY_FUNCTION NotifyFunction + ) +{ + SMBUS_INSTANCE *Private; + + DEBUG ((EFI_D_INFO, "PEI SmbusNotify() Start\n")); + + Private = SMBUS_PRIVATE_DATA_FROM_PPI_THIS (This); + + if (NotifyFunction == NULL) { + return EFI_INVALID_PARAMETER; + } + /// + /// NOTE: Currently there is no periodic event in PEI. + /// So we just check the Notification at the end of in each + /// Smbus.Execute function. + /// + if (Private->NotifyFunctionNum >= MAX_SMBUS_NOTIFICATION) { + return EFI_OUT_OF_RESOURCES; + } + + Private->NotifyFunctionList[Private->NotifyFunctionNum].SlaveAddress.SmbusDeviceAddress = SlaveAddress.SmbusDeviceAddress; + Private->NotifyFunctionList[Private->NotifyFunctionNum].Data = Data; + Private->NotifyFunctionList[Private->NotifyFunctionNum].NotifyFunction = NotifyFunction; + Private->NotifyFunctionNum++; + + /// + /// Last step, check notification + /// + CheckNotification (Private); + + DEBUG ((EFI_D_INFO, "PEI SmbusNotify() End\n")); + + return EFI_SUCCESS; +} + +/** + This function gets called back at the end of PEI if any devices were ARPed + during PEI. It will build a HOB to describe to DXE what devices were ARPed. + + @param[in] PeiServices General purpose services available to every PEIM. + @param[in] NotifyDescriptor The notification structure this PEIM registered on install. + @param[in] Ppi The EndOfPeiSignal PPI. + + @retval EFI_SUCCESS The function completed successfully. +**/ +EFI_STATUS +EndOfPeiCallback ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, + IN VOID *Ppi + ) +{ + EFI_STATUS Status; + EFI_PEI_PPI_DESCRIPTOR *SmbusDescriptor; + PEI_SMBUS_PPI *SmbusPpi; + SMBUS_INSTANCE *Private; + UINTN BufferSize; + VOID *Hob; + + DEBUG ((EFI_D_INFO, "PEI EndOfPeiCallback() Start\n")); + + Status = (**PeiServices).LocatePpi ( + PeiServices, + &gPeiSmbusPpiGuid, /// GUID + 0, /// INSTANCE + &SmbusDescriptor, /// PEI_PPI_DESCRIPTOR + &SmbusPpi /// PPI + ); + ASSERT_EFI_ERROR (Status); + + Private = SMBUS_PRIVATE_DATA_FROM_DESCRIPTOR_THIS (SmbusDescriptor); + BufferSize = sizeof (EFI_SMBUS_DEVICE_MAP) * Private->DeviceMapEntries; + + Hob = BuildGuidDataHob ( + &mEfiSmbusArpMapGuid, + Private->DeviceMap, + BufferSize + ); + ASSERT (Hob != NULL); + + DEBUG ((EFI_D_INFO, "PEI EndOfPeiCallback() End\n")); + + return EFI_SUCCESS; +} + +/** + Function to be called when SMBus.Execute happens. This will check if + the SMBus Host Controller has received a Host Notify command. If so, it will + see if a notification has been reqested on that event and make any callbacks + that may be necessary. + + @param[in] Private Pointer to the SMBUS_INSTANCE + + @retval None +**/ +VOID +CheckNotification ( + IN SMBUS_INSTANCE *Private + ) +{ + EFI_SMBUS_DEVICE_ADDRESS SlaveAddress; + UINT8 SstsReg; + UINTN Data; + UINTN Index; + + DEBUG ((EFI_D_INFO, "PEI CheckNotification() Start\n")); + + if (Private->NotifyFunctionNum == 0) { + /// + /// Since no one register it, not need to check. + /// + return; + } + + SstsReg = SmbusIoRead (R_PCH_SMBUS_SSTS); + if (!(SstsReg & B_PCH_SMBUS_HOST_NOTIFY_STS)) { + /// + /// Host Notify has not been received + /// + return; + } + /// + /// There was a Host Notify, see if any one wants to know about it + /// + SlaveAddress.SmbusDeviceAddress = (SmbusIoRead (R_PCH_SMBUS_NDA)) >> 1; + + for (Index = 0; Index < Private->NotifyFunctionNum; Index++) { + + if (Private->NotifyFunctionList[Index].SlaveAddress.SmbusDeviceAddress == SlaveAddress.SmbusDeviceAddress) { + Data = (SmbusIoRead (R_PCH_SMBUS_NDHB) << 8) + (SmbusIoRead (R_PCH_SMBUS_NDLB)); + if ((UINT16) Private->NotifyFunctionList[Index].Data == (UINT16) Data) { + /// + /// We have a match, notify the requested function + /// + Private->NotifyFunctionList[Index].NotifyFunction ( + Private->PeiServices, + &Private->SmbusPpi, + SlaveAddress, + Data + ); + } + } + } + /// + /// Clear the Notify Status bit and exit. + /// + SmbusIoWrite (R_PCH_SMBUS_SSTS, B_PCH_SMBUS_HOST_NOTIFY_STS); + + DEBUG ((EFI_D_INFO, "PEI CheckNotification() End\n")); +} |