5 * Implement External, AGESA Common, and CPU component General Services.
7 * Contains implementation of the interfaces: General Services API in AGESA.h,
8 * GeneralServices.h, and cpuServices.h.
10 * @xrefitem bom "File Content Label" "Release Content"
13 * @e \$Revision: 44324 $ @e \$Date: 2010-12-22 17:16:51 +0800 (Wed, 22 Dec 2010) $
17 ******************************************************************************
19 * Copyright (c) 2011, Advanced Micro Devices, Inc.
20 * All rights reserved.
22 * Redistribution and use in source and binary forms, with or without
23 * modification, are permitted provided that the following conditions are met:
24 * * Redistributions of source code must retain the above copyright
25 * notice, this list of conditions and the following disclaimer.
26 * * Redistributions in binary form must reproduce the above copyright
27 * notice, this list of conditions and the following disclaimer in the
28 * documentation and/or other materials provided with the distribution.
29 * * Neither the name of Advanced Micro Devices, Inc. nor the names of
30 * its contributors may be used to endorse or promote products derived
31 * from this software without specific prior written permission.
33 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
34 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
35 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 * DISCLAIMED. IN NO EVENT SHALL ADVANCED MICRO DEVICES, INC. BE LIABLE FOR ANY
37 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
38 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
39 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
40 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
41 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
42 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
43 ******************************************************************************
46 /*----------------------------------------------------------------------------------------
47 * M O D U L E S U S E D
48 *----------------------------------------------------------------------------------------
55 #include "cpuRegisters.h"
56 #include "GeneralServices.h"
57 #include "cpuFamilyTranslation.h"
58 #include "cpuServices.h"
59 #include "heapManager.h"
60 #include "cpuApicUtilities.h"
63 RDATA_GROUP (G1_PEICC)
65 #define FILECODE PROC_CPU_CPUGENERALSERVICES_FILECODE
66 /*----------------------------------------------------------------------------------------
67 * D E F I N I T I O N S A N D M A C R O S
68 *----------------------------------------------------------------------------------------
70 extern OPTIONS_CONFIG_TOPOLOGY TopologyConfiguration;
71 extern BUILD_OPT_CFG UserOptions;
73 /*----------------------------------------------------------------------------------------
74 * T Y P E D E F S A N D S T R U C T U R E S
75 *----------------------------------------------------------------------------------------
78 /*----------------------------------------------------------------------------------------
79 * P R O T O T Y P E S O F L O C A L F U N C T I O N S
80 *----------------------------------------------------------------------------------------
83 /*----------------------------------------------------------------------------------------
84 * E X P O R T E D F U N C T I O N S - External General Services API
85 *----------------------------------------------------------------------------------------
89 * Get a specified Core's APIC ID.
91 * Invoke corresponding Cpu Service for external user.
93 * @param[in,out] AmdParamApic Our interface struct
95 * @return The most severe status of any called service.
99 IN OUT AMD_APIC_PARAMS *AmdParamApic
102 AGESA_STATUS AgesaStatus;
104 AGESA_TESTPOINT (TpIfAmdGetApicIdEntry, &AmdParamApic->StdHeader);
105 AmdParamApic->StdHeader.HeapBasePtr = HeapGetBaseAddress (&AmdParamApic->StdHeader);
107 AmdParamApic->IsPresent = GetApicId (
108 &AmdParamApic->StdHeader,
109 AmdParamApic->Socket,
111 &AmdParamApic->ApicAddress,
115 AGESA_TESTPOINT (TpIfAmdGetApicIdExit, &AmdParamApic->StdHeader);
120 * Get Processor Module's PCI Config Space address.
122 * Invoke corresponding Cpu Service for external user.
124 * @param[in,out] AmdParamGetPci Our interface struct
126 * @return The most severe status of any called service.
130 IN OUT AMD_GET_PCI_PARAMS *AmdParamGetPci
133 AGESA_STATUS AgesaStatus;
135 AGESA_TESTPOINT (TpIfAmdGetPciAddressEntry, &AmdParamGetPci->StdHeader);
136 AmdParamGetPci->StdHeader.HeapBasePtr = HeapGetBaseAddress (&AmdParamGetPci->StdHeader);
138 AmdParamGetPci->IsPresent = GetPciAddress (
139 &AmdParamGetPci->StdHeader,
140 AmdParamGetPci->Socket,
141 AmdParamGetPci->Module,
142 &AmdParamGetPci->PciAddress,
146 AGESA_TESTPOINT (TpIfAmdGetPciAddressExit, &AmdParamGetPci->StdHeader);
151 * "Who am I" for the current running core.
153 * Invoke corresponding Cpu Service for external user.
155 * @param[in,out] AmdParamIdentify Our interface struct
157 * @return The most severe status of any called service.
161 IN OUT AMD_IDENTIFY_PARAMS *AmdParamIdentify
164 AGESA_STATUS AgesaStatus;
169 AGESA_TESTPOINT (TpIfAmdIdentifyCoreEntry, &AmdParamIdentify->StdHeader);
170 AmdParamIdentify->StdHeader.HeapBasePtr = HeapGetBaseAddress (&AmdParamIdentify->StdHeader);
173 &AmdParamIdentify->StdHeader,
179 AmdParamIdentify->Socket = (UINT8)Socket;
180 AmdParamIdentify->Module = (UINT8)Module;
181 AmdParamIdentify->Core = (UINT8)Core;
183 AGESA_TESTPOINT (TpIfAmdIdentifyCoreExit, &AmdParamIdentify->StdHeader);
187 /*----------------------------------------------------------------------------------------
188 * E X P O R T E D F U N C T I O N S - AGESA common General Services
189 *----------------------------------------------------------------------------------------
192 /*---------------------------------------------------------------------------------------*/
194 * Get a specified Core's APIC ID.
196 * Code sync: This calculation MUST match the assignment
197 * calculation done in LocalApicInitializationAtEarly function.
199 * @param[in] StdHeader Header for library and services.
200 * @param[in] Socket The socket in which the Core's Processor is installed.
201 * @param[in] Core The Core id.
202 * @param[out] ApicAddress The Core's APIC ID.
203 * @param[out] AgesaStatus Aggregates AGESA_STATUS for external interface, Always Succeeds.
205 * @retval TRUE The core is present, APIC Id valid
206 * @retval FALSE The core is not present, APIC Id not valid.
210 IN AMD_CONFIG_PARAMS *StdHeader,
213 OUT UINT8 *ApicAddress,
214 OUT AGESA_STATUS *AgesaStatus
222 if (GetActiveCoresInGivenSocket (Socket, &CoreCount, StdHeader)) {
223 if (Core < CoreCount) {
225 GetLocalApicIdForCore (Socket, Core, &ApicID, StdHeader);
226 *ApicAddress = (UINT8) ApicID;
231 *AgesaStatus = AGESA_SUCCESS;
236 /*---------------------------------------------------------------------------------------*/
238 * Get Processor Module's PCI Config Space address.
240 * @param[in] StdHeader Header for library and services.
241 * @param[in] Socket The Core's Socket.
242 * @param[in] Module The Module in that Processor
243 * @param[out] PciAddress The Processor's PCI Config Space address (Function 0, Register 0)
244 * @param[out] AgesaStatus Aggregates AGESA_STATUS for external interface, Always Succeeds.
246 * @retval TRUE The core is present, PCI Address valid
247 * @retval FALSE The core is not present, PCI Address not valid.
251 IN AMD_CONFIG_PARAMS *StdHeader,
254 OUT PCI_ADDR *PciAddress,
255 OUT AGESA_STATUS *AgesaStatus
261 ASSERT (Socket < MAX_SOCKETS);
262 ASSERT (Module < MAX_DIES);
266 *AgesaStatus = AGESA_SUCCESS;
268 if (GetNodeId (Socket, Module, &Node, StdHeader)) {
269 // socket is populated
270 PciAddress->AddressValue = MAKE_SBDFO (0, 0, 24, 0, 0);
271 PciAddress->Address.Device = PciAddress->Address.Device + Node;
273 // socket is not populated
274 PciAddress->AddressValue = ILLEGAL_SBDFO;
280 /*---------------------------------------------------------------------------------------*/
282 * "Who am I" for the current running core.
284 * @param[in] StdHeader Header for library and services.
285 * @param[out] Socket The current Core's Socket
286 * @param[out] Module The current Core's Processor Module
287 * @param[out] Core The current Core's core id.
288 * @param[out] AgesaStatus Aggregates AGESA_STATUS for external interface, Always Succeeds.
293 IN AMD_CONFIG_PARAMS *StdHeader,
297 OUT AGESA_STATUS *AgesaStatus
300 AP_MAIL_INFO ApMailboxInfo;
304 *AgesaStatus = AGESA_SUCCESS;
306 GetApMailbox (&ApMailboxInfo.Info, StdHeader);
307 ASSERT (ApMailboxInfo.Fields.Socket < MAX_SOCKETS);
308 ASSERT (ApMailboxInfo.Fields.Module < MAX_DIES);
309 *Socket = (UINT8)ApMailboxInfo.Fields.Socket;
310 *Module = (UINT8)ApMailboxInfo.Fields.Module;
313 GetCurrentCore (&CurrentCore, StdHeader);
314 *Core = (UINT8)CurrentCore;
318 /*----------------------------------------------------------------------------------------
319 * E X P O R T E D F U N C T I O N S - cpu component General Services
320 *----------------------------------------------------------------------------------------
323 /*---------------------------------------------------------------------------------------*/
325 * Get the current Platform's number of Sockets, regardless of how many are populated.
327 * The Options component can provide how many sockets are available in system.
328 * This can be used to avoid testing presence of Processors in Sockets which don't exist.
329 * The result can be one socket to the maximum possible sockets of any supported processor family.
330 * You cannot assume that all sockets contain a processor or that the sockets have processors
331 * installed in any particular order. Do not convert this number to a number of nodes.
333 * @return The number of available sockets for the platform.
337 GetPlatformNumberOfSockets ()
339 return TopologyConfiguration.PlatformNumberOfSockets;
342 /*---------------------------------------------------------------------------------------*/
344 * Get the number of Modules to check presence in each Processor.
346 * The Options component can provide how many modules need to be check for presence in each
347 * processor, regardless whether all, or any, processor have that many modules present on this boot.
348 * The result can be one module to the maximum possible modules of any supported processor family.
349 * You cannot assume that Modules are in any particular order, especially with respect to node id.
351 * @return The maximum number of modules in each processor.
355 GetPlatformNumberOfModules ()
357 return TopologyConfiguration.PlatformNumberOfModules;
360 /*---------------------------------------------------------------------------------------*/
362 * Is a processor present in Socket?
364 * Check to see if any possible module of the processor is present. This provides
365 * support for a few cases where a PCI address isn't needed, but code still needs to
368 * @param[in] Socket The socket which is being tested
369 * @param[in] StdHeader Header for library and services.
371 * @retval TRUE The socket has a processor installed
372 * @retval FALSE The socket is empty (or the processor is dead).
378 IN AMD_CONFIG_PARAMS *StdHeader
381 SOCKET_DIE_TO_NODE_MAP pSocketDieMap;
382 LOCATE_HEAP_PTR SocketDieHeapDataBlock;
387 ASSERT (Socket < MAX_SOCKETS);
389 SocketDieHeapDataBlock.BufferHandle = SOCKET_DIE_MAP_HANDLE;
391 // Get data block from heap
392 Status = HeapLocateBuffer (&SocketDieHeapDataBlock, StdHeader);
393 pSocketDieMap = (SOCKET_DIE_TO_NODE_MAP)SocketDieHeapDataBlock.BufferPtr;
394 ASSERT ((pSocketDieMap != NULL) && (Status == AGESA_SUCCESS));
395 for (Module = 0; Module < GetPlatformNumberOfModules (); Module++) {
396 if ((*pSocketDieMap)[Socket][Module].Node != 0xFF) {
404 /*---------------------------------------------------------------------------------------*/
406 * Provide the number of installed processors (not Nodes! and not Sockets!)
408 * Iterate over the Socket, Module to Node Map, counting the number of present nodes.
409 * Do not use this as a Node Count! Do not use this as the number of Sockets! (This
410 * is for APIC ID utilities.)
412 * @param[in] StdHeader Header for library and services.
414 * @return the number of processors installed
418 GetNumberOfProcessors (
419 IN AMD_CONFIG_PARAMS *StdHeader
422 SOCKET_DIE_TO_NODE_MAP pSocketDieMap;
423 LOCATE_HEAP_PTR SocketDieHeapDataBlock;
430 SocketDieHeapDataBlock.BufferHandle = SOCKET_DIE_MAP_HANDLE;
432 // Get data block from heap
433 Status = HeapLocateBuffer (&SocketDieHeapDataBlock, StdHeader);
434 pSocketDieMap = (SOCKET_DIE_TO_NODE_MAP)SocketDieHeapDataBlock.BufferPtr;
435 ASSERT ((pSocketDieMap != NULL) && (Status == AGESA_SUCCESS));
436 for (Socket = 0; Socket < GetPlatformNumberOfSockets (); Socket++) {
437 for (Module = 0; Module < GetPlatformNumberOfModules (); Module++) {
438 if ((*pSocketDieMap)[Socket][Module].Node != 0xFF) {
447 /*---------------------------------------------------------------------------------------*/
449 * For a specific Node, get its Socket and Module ids.
451 * If asking for the current running Node, read the mailbox socket, module. Specific Node,
452 * locate the Node to Socket/Module Map in heap, and return the ids, if present.
454 * @param[in] Node What Socket and Module is this Node?
455 * @param[out] Socket The Socket containing that Node.
456 * @param[out] Module The Processor Module of that Node.
457 * @param[in] StdHeader Header for library and services.
459 * @retval TRUE Node is present, Socket, Module are valid.
460 * @retval FALSE Node is not present, why do you ask?
463 GetSocketModuleOfNode (
467 IN AMD_CONFIG_PARAMS *StdHeader
470 NODE_TO_SOCKET_DIE_MAP pNodeMap;
471 LOCATE_HEAP_PTR SocketDieHeapDataBlock;
477 ASSERT (Node < MAX_NODES);
480 SocketDieHeapDataBlock.BufferHandle = NODE_ID_MAP_HANDLE;
481 Status = HeapLocateBuffer (&SocketDieHeapDataBlock, StdHeader);
482 pNodeMap = (NODE_TO_SOCKET_DIE_MAP)SocketDieHeapDataBlock.BufferPtr;
483 ASSERT ((pNodeMap != NULL) && (Status == AGESA_SUCCESS));
484 *Socket = (*pNodeMap)[Node].Socket;
485 *Module = (*pNodeMap)[Node].Die;
486 if ((*pNodeMap)[Node].Socket != 0xFF) {
492 /*---------------------------------------------------------------------------------------*/
494 * Get the current core's Processor APIC Index.
496 * The Processor APIC Index is the position of the current processor in the APIC id
497 * assignment. Processors are ordered in node id order. This is not the same, however,
498 * as the node id of the current socket and module or the current socket id.
500 * @param[in] Node The current desired core's node id (usually the current core).
501 * @param[in] StdHeader Header for library and services.
503 * @return Processor APIC Index
507 GetProcessorApicIndex (
509 IN AMD_CONFIG_PARAMS *StdHeader
512 UINT32 ProcessorApicIndex;
513 UINT32 PreviousSocket;
514 UINT32 CurrentSocket;
518 ASSERT (Node < MAX_NODES);
520 // Calculate total APIC devices up to Current Node, Core.
521 ProcessorApicIndex = 0;
522 PreviousSocket = 0xFF;
523 for (i = 0; i < (Node + 1); i++) {
524 GetSocketModuleOfNode (i, &CurrentSocket, &Ignored, StdHeader);
525 if (CurrentSocket != PreviousSocket) {
526 ProcessorApicIndex++;
527 PreviousSocket = CurrentSocket;
530 // Convert to Index (zero based) from count (one based).
531 ProcessorApicIndex--;
532 return ProcessorApicIndex;
535 /*---------------------------------------------------------------------------------------*/
537 * Returns current node number
539 * @param[out] Node This Core's Node id
540 * @param[in] StdHeader Header for library and services.
546 IN AMD_CONFIG_PARAMS *StdHeader
549 AP_MAIL_INFO ApMailboxInfo;
551 // Get the Node Id from the Mailbox.
552 GetApMailbox (&ApMailboxInfo.Info, StdHeader);
553 ASSERT (ApMailboxInfo.Fields.Node < MAX_NODES);
554 *Node = ApMailboxInfo.Fields.Node;
557 /*---------------------------------------------------------------------------------------*/
559 * Writes to all nodes on the executing core's socket.
561 * @param[in] PciAddress The Function and Register to update
562 * @param[in] Mask The bitwise AND mask to apply to the current register value
563 * @param[in] Data The bitwise OR mask to apply to the current register value
564 * @param[in] StdHeader Header for library and services.
568 ModifyCurrentSocketPci (
569 IN PCI_ADDR *PciAddress,
572 IN AMD_CONFIG_PARAMS *StdHeader
578 UINT32 LocalPciRegister;
579 AGESA_STATUS AgesaStatus;
582 IdentifyCore (StdHeader, &Socket, &Module, &Core, &AgesaStatus);
584 for (Module = 0; Module < (UINT8)GetPlatformNumberOfModules (); Module++) {
585 if (GetPciAddress (StdHeader, Socket, Module, &Reg, &AgesaStatus)) {
586 Reg.Address.Function = PciAddress->Address.Function;
587 Reg.Address.Register = PciAddress->Address.Register;
588 LibAmdPciRead (AccessWidth32, Reg, &LocalPciRegister, StdHeader);
589 LocalPciRegister &= Mask;
590 LocalPciRegister |= Data;
591 LibAmdPciWrite (AccessWidth32, Reg, &LocalPciRegister, StdHeader);
596 /*---------------------------------------------------------------------------------------*/
598 * Returns Total number of active cores in the current socket
600 * @param[out] CoreCount The cores in this processor.
601 * @param[in] StdHeader Header for library and services.
605 GetActiveCoresInCurrentSocket (
606 OUT UINT32 *CoreCount,
607 IN AMD_CONFIG_PARAMS *StdHeader
610 CPUID_DATA CpuidDataStruct;
611 UINT32 TotalCoresCount;
613 LibAmdCpuidRead (AMD_CPUID_ASIZE_PCCOUNT, &CpuidDataStruct, StdHeader);
614 TotalCoresCount = (CpuidDataStruct.ECX_Reg & 0x000000FF) + 1;
615 *CoreCount = TotalCoresCount;
618 /*---------------------------------------------------------------------------------------*/
620 * Provides the Total number of active cores in the current core's node.
622 * @param[in] StdHeader Header for library and services.
624 * @return The current node core count
627 GetActiveCoresInCurrentModule (
628 IN AMD_CONFIG_PARAMS *StdHeader
636 UINT32 ProcessorCoreCount;
637 AGESA_STATUS AgesaStatus;
639 ProcessorCoreCount = 0;
641 IdentifyCore (StdHeader, &Socket, &Module, &Core, &AgesaStatus);
642 if (GetGivenModuleCoreRange (Socket, Module, &LowCore, &HighCore, StdHeader)) {
643 ProcessorCoreCount = ((HighCore - LowCore) + 1);
645 return ProcessorCoreCount;
649 * Provide the number of compute units on current module.
652 * @param[in] StdHeader Header for library and services.
654 * @return The current compute unit counts.
658 GetNumberOfCompUnitsInCurrentModule (
659 IN AMD_CONFIG_PARAMS *StdHeader
665 UINT32 ComputeUnitCount;
667 AGESA_STATUS IgnoredSts;
668 LOCATE_HEAP_PTR SocketDieHeapDataBlock;
669 SOCKET_DIE_TO_NODE_MAP pSocketDieMap;
671 ComputeUnitCount = 0;
673 ASSERT ((GetComputeUnitMapping (StdHeader) == AllCoresMapping) ||
674 (GetComputeUnitMapping (StdHeader) == EvenCoresMapping));
676 IdentifyCore (StdHeader, &Socket, &Module, &CurrentCore, &IgnoredSts);
677 // Get data block from heap
678 SocketDieHeapDataBlock.BufferHandle = SOCKET_DIE_MAP_HANDLE;
679 IgnoredSts = HeapLocateBuffer (&SocketDieHeapDataBlock, StdHeader);
680 pSocketDieMap = (SOCKET_DIE_TO_NODE_MAP)SocketDieHeapDataBlock.BufferPtr;
681 ASSERT ((pSocketDieMap != NULL) && (IgnoredSts == AGESA_SUCCESS));
682 // Current Core's socket, module must be present.
683 ASSERT ((*pSocketDieMap)[Socket][Module].Node != 0xFF);
684 // Process compute unit info
685 Enabled = (*pSocketDieMap)[Socket][Module].EnabledComputeUnits;
687 while (Enabled > 0) {
688 if ((Enabled & 0x1) != 0) {
694 return ComputeUnitCount;
697 /*---------------------------------------------------------------------------------------*/
699 * Provides the Total number of active cores in the given socket.
701 * @param[in] Socket Get a core count for the processor in this socket.
702 * @param[out] CoreCount Its core count
703 * @param[in] StdHeader Header for library and services.
705 * @retval TRUE A processor is present in the Socket and the CoreCount is valid.
706 * @retval FALSE The Socket does not have a Processor
709 GetActiveCoresInGivenSocket (
711 OUT UINT32 *CoreCount,
712 IN AMD_CONFIG_PARAMS *StdHeader
718 UINT32 ProcessorCoreCount;
722 ProcessorCoreCount = 0;
724 for (Module = 0; Module < GetPlatformNumberOfModules (); Module++) {
725 if (GetGivenModuleCoreRange (Socket, Module, &LowCore, &HighCore, StdHeader)) {
726 ProcessorCoreCount = ProcessorCoreCount + ((HighCore - LowCore) + 1);
732 *CoreCount = ProcessorCoreCount;
736 /*---------------------------------------------------------------------------------------*/
738 * Provides the range of Cores in a Processor which are in a Module.
740 * Cores are named uniquely in a processor, 0 to TotalCores. Any module in the processor has
741 * a set of those cores, named from LowCore to HighCore.
743 * @param[in] Socket Get a core range for the processor in this socket.
744 * @param[in] Module Get a core range for this Module in the processor.
745 * @param[out] LowCore The lowest Processor Core in the Module.
746 * @param[out] HighCore The highest Processor Core in the Module.
747 * @param[in] StdHeader Header for library and services.
749 * @retval TRUE A processor is present in the Socket and the Core Range is valid.
750 * @retval FALSE The Socket does not have a Processor
753 GetGivenModuleCoreRange (
757 OUT UINT32 *HighCore,
758 IN AMD_CONFIG_PARAMS *StdHeader
761 SOCKET_DIE_TO_NODE_MAP pSocketDieMap;
762 LOCATE_HEAP_PTR SocketDieHeapDataBlock;
766 ASSERT (Socket < MAX_SOCKETS);
767 ASSERT (Module < MAX_DIES);
769 SocketDieHeapDataBlock.BufferHandle = SOCKET_DIE_MAP_HANDLE;
771 // Get data block from heap
772 Status = HeapLocateBuffer (&SocketDieHeapDataBlock, StdHeader);
773 pSocketDieMap = (SOCKET_DIE_TO_NODE_MAP)SocketDieHeapDataBlock.BufferPtr;
774 ASSERT ((pSocketDieMap != NULL) && (Status == AGESA_SUCCESS));
775 *LowCore = (*pSocketDieMap)[Socket][Module].LowCore;
776 *HighCore = (*pSocketDieMap)[Socket][Module].HighCore;
777 if ((*pSocketDieMap)[Socket][Module].Node != 0xFF) {
783 /*---------------------------------------------------------------------------------------*/
785 * Returns the current running core number.
787 * @param[out] Core The core id.
788 * @param[in] StdHeader Header for library and services.
794 IN AMD_CONFIG_PARAMS *StdHeader
797 CPUID_DATA CpuidDataStruct;
799 UINT32 ApicIdCoreIdSize;
800 CORE_ID_POSITION InitApicIdCpuIdLo;
801 CPU_SPECIFIC_SERVICES *FamilyServices;
803 GetCpuServicesOfCurrentCore ((const CPU_SPECIFIC_SERVICES **)&FamilyServices, StdHeader);
804 ASSERT (FamilyServices != NULL);
806 // Read CPUID ebx[31:24] to get initial APICID
807 LibAmdCpuidRead (AMD_CPUID_APICID_LPC_BID, &CpuidDataStruct, StdHeader);
808 LocalApicId = (CpuidDataStruct.EBX_Reg & 0xFF000000) >> 24;
810 // Find the core ID size.
811 LibAmdCpuidRead (AMD_CPUID_ASIZE_PCCOUNT, &CpuidDataStruct, StdHeader);
812 ApicIdCoreIdSize = (CpuidDataStruct.ECX_Reg & 0x0000F000) >> 12;
814 InitApicIdCpuIdLo = FamilyServices->CoreIdPositionInInitialApicId (FamilyServices, StdHeader);
815 ASSERT (InitApicIdCpuIdLo < CoreIdPositionMax);
817 // Now extract the core ID from the Apic ID by right justifying the id and masking off non-core Id bits.
818 *Core = ((LocalApicId >> ((1 - (UINT32)InitApicIdCpuIdLo) * (MAX_CORE_ID_SIZE - ApicIdCoreIdSize))) &
819 (MAX_CORE_ID_MASK >> (MAX_CORE_ID_SIZE - ApicIdCoreIdSize)));
822 /*---------------------------------------------------------------------------------------*/
824 * Returns current node, and core number.
826 * @param[out] Node The node id of the current core's node.
827 * @param[out] Core The core id if the current core.
828 * @param[in] StdHeader Config handle for library and services.
832 GetCurrentNodeAndCore (
835 IN AMD_CONFIG_PARAMS *StdHeader
839 GetCurrentNodeNum (Node, StdHeader);
842 GetCurrentCore (Core, StdHeader);
845 /*---------------------------------------------------------------------------------------*/
847 * Is the current core a primary core of it's node?
849 * @param[in] StdHeader Config handle for library and services.
851 * @retval TRUE Is Primary Core
852 * @retval FALSE Is not Primary Core
856 IsCurrentCorePrimary (
857 IN AMD_CONFIG_PARAMS *StdHeader
866 AGESA_STATUS IgnoredSts;
870 IdentifyCore (StdHeader, &Socket, &Module, &Core, &IgnoredSts);
871 GetGivenModuleCoreRange (Socket, Module, &PrimaryCore, &IgnoredCore, StdHeader);
872 if (Core == PrimaryCore) {
879 /*---------------------------------------------------------------------------------------*/
881 * Returns node id based on SocketId and ModuleId.
883 * @param[in] SocketId The socket to look up
884 * @param[in] ModuleId The module in that socket
885 * @param[out] NodeId Provide the corresponding Node Id.
886 * @param[in] StdHeader Handle of Header for calling lib functions and services.
888 * @retval TRUE The socket is populated
889 * @retval FALSE The socket is not populated
897 IN AMD_CONFIG_PARAMS *StdHeader
900 SOCKET_DIE_TO_NODE_MAP pSocketDieMap;
901 LOCATE_HEAP_PTR SocketDieHeapDataBlock;
906 SocketDieHeapDataBlock.BufferHandle = SOCKET_DIE_MAP_HANDLE;
908 // Get data block from heap
909 Status = HeapLocateBuffer (&SocketDieHeapDataBlock, StdHeader);
910 pSocketDieMap = (SOCKET_DIE_TO_NODE_MAP)SocketDieHeapDataBlock.BufferPtr;
911 ASSERT ((pSocketDieMap != NULL) && (Status == AGESA_SUCCESS));
912 *NodeId = (*pSocketDieMap)[SocketId][ModuleId].Node;
913 if ((*pSocketDieMap)[SocketId][ModuleId].Node != 0xFF) {
919 /*---------------------------------------------------------------------------------------*/
921 * Get the cached AP Mailbox Info if available, or read the info from the hardware.
923 * Locate the known AP Mailbox Info Cache buffer in this core's local heap. If it
924 * doesn't exist, read the hardware to get the info.
925 * This routine gets the main AP mailbox, not the system degree.
927 * @param[out] ApMailboxInfo Provide the info in this AP core's mailbox
928 * @param[in] StdHeader Config handle for library and services.
933 OUT UINT32 *ApMailboxInfo,
934 IN AMD_CONFIG_PARAMS *StdHeader
937 AGESA_STATUS Ignored;
938 LOCATE_HEAP_PTR LocalApMailboxCache;
939 CPU_SPECIFIC_SERVICES *FamilyServices;
940 AP_MAILBOXES ApMailboxes;
943 IamBsp = IsBsp (StdHeader, &Ignored);
944 LocalApMailboxCache.BufferHandle = LOCAL_AP_MAIL_BOX_CACHE_HANDLE;
945 if (((StdHeader->HeapStatus == HEAP_LOCAL_CACHE) || IamBsp) &&
946 (HeapLocateBuffer (&LocalApMailboxCache, StdHeader) == AGESA_SUCCESS)) {
947 // If during HEAP_LOCAL_CACHE stage, we always try to get ApMailbox from heap
948 // If we're not in HEAP_LOCAL_CACHE stage, only BSP can get ApMailbox from heap
949 *ApMailboxInfo = ((AP_MAILBOXES *) LocalApMailboxCache.BufferPtr)->ApMailInfo.Info;
950 } else if (!IamBsp) {
951 // If this is an AP, the hardware register should be good.
952 GetCpuServicesOfCurrentCore ((const CPU_SPECIFIC_SERVICES **)&FamilyServices, StdHeader);
953 ASSERT (FamilyServices != NULL);
954 FamilyServices->GetApMailboxFromHardware (FamilyServices, &ApMailboxes, StdHeader);
955 *ApMailboxInfo = ApMailboxes.ApMailInfo.Info;
957 // This is the BSC. The hardware mailbox has not been set up yet.
962 /*---------------------------------------------------------------------------------------*/
964 * Cache the Ap Mailbox info in our local heap for later use.
966 * This enables us to use the info even after the mailbox register is initialized
967 * with operational values. Get all the AP mailboxes and keep them in one buffer.
969 * @param[in] StdHeader Config handle for library and services.
974 IN AMD_CONFIG_PARAMS *StdHeader
977 ALLOCATE_HEAP_PARAMS AllocHeapParams;
978 AP_MAILBOXES ApMailboxes;
979 CPU_SPECIFIC_SERVICES *FamilyServices;
981 GetCpuServicesOfCurrentCore ((const CPU_SPECIFIC_SERVICES **)&FamilyServices, StdHeader);
982 ASSERT (FamilyServices != NULL);
984 // Get mailbox from hardware.
985 FamilyServices->GetApMailboxFromHardware (FamilyServices, &ApMailboxes, StdHeader);
987 // Allocate heap for the info
988 AllocHeapParams.RequestedBufferSize = sizeof (AP_MAILBOXES);
989 AllocHeapParams.BufferHandle = LOCAL_AP_MAIL_BOX_CACHE_HANDLE;
990 AllocHeapParams.Persist = HEAP_SYSTEM_MEM;
991 if (HeapAllocateBuffer (&AllocHeapParams, StdHeader) == AGESA_SUCCESS) {
992 *(AP_MAILBOXES *)AllocHeapParams.BufferPtr = ApMailboxes;
996 /*---------------------------------------------------------------------------------------*/
998 * Compute the degree of the system.
1000 * The degree of a system is the maximum degree of any node. The degree of a node is the
1001 * number of nodes to which it is directly connected (not considering width or redundant
1004 * @param[in] StdHeader Config handle for library and services.
1009 IN AMD_CONFIG_PARAMS *StdHeader
1012 AP_MAILBOXES *ApMailboxes;
1013 LOCATE_HEAP_PTR LocalApMailboxCache;
1014 AGESA_STATUS Status;
1016 // Get data block from heap
1017 LocalApMailboxCache.BufferHandle = LOCAL_AP_MAIL_BOX_CACHE_HANDLE;
1018 Status = HeapLocateBuffer (&LocalApMailboxCache, StdHeader);
1019 // non-Success handled by ASSERT not NULL below.
1020 ApMailboxes = (AP_MAILBOXES *)LocalApMailboxCache.BufferPtr;
1021 ASSERT ((ApMailboxes != NULL) && (Status == AGESA_SUCCESS));
1022 return ApMailboxes->ApMailExtInfo.Fields.SystemDegree;
1025 /*---------------------------------------------------------------------------------------*/
1027 * Spins until the number of microseconds specified have
1028 * expired regardless of CPU operational frequency.
1030 * @param[in] Microseconds Wait time in microseconds
1031 * @param[in] StdHeader Header for library and services
1036 IN UINT32 Microseconds,
1037 IN AMD_CONFIG_PARAMS *StdHeader
1040 UINT32 TscRateInMhz;
1041 UINT64 NumberOfTicks;
1044 CPU_SPECIFIC_SERVICES *FamilySpecificServices;
1046 LibAmdMsrRead (TSC, &InitialTsc, StdHeader);
1047 GetCpuServicesOfCurrentCore ((const CPU_SPECIFIC_SERVICES **)&FamilySpecificServices, StdHeader);
1048 FamilySpecificServices->GetTscRate (FamilySpecificServices, &TscRateInMhz, StdHeader);
1049 NumberOfTicks = Microseconds * TscRateInMhz;
1051 LibAmdMsrRead (TSC, &CurrentTsc, StdHeader);
1052 } while ((CurrentTsc - InitialTsc) < NumberOfTicks);
1055 /*---------------------------------------------------------------------------------------*/
1057 * A boolean function determine executed CPU is BSP core.
1059 * @param[in,out] StdHeader Header for library and services
1060 * @param[out] AgesaStatus Aggregates AGESA_STATUS for external interface, Always Succeeds.
1065 IN OUT AMD_CONFIG_PARAMS *StdHeader,
1066 OUT AGESA_STATUS *AgesaStatus
1072 *AgesaStatus = AGESA_SUCCESS;
1074 // Read APIC_BASE register (0x1B), bit[8] returns 1 for BSP
1075 LibAmdMsrRead (MSR_APIC_BAR, &MsrData, StdHeader);
1076 if ((MsrData & BIT8) != 0 ) {
1084 /*---------------------------------------------------------------------------------------*/
1086 * Get the compute unit mapping algorithm.
1088 * Look up the compute unit values for the current core's socket/module and find the matching
1089 * core pair map item. This will tell us how to determine the core's status.
1091 * @param[in] StdHeader Header for library and services
1093 * @retval AllCoresMapping Each core is in a compute unit of its own.
1094 * @retval EvenCoresMapping Even/Odd pairs of cores are in each compute unit.
1096 COMPUTE_UNIT_MAPPING
1097 GetComputeUnitMapping (
1098 IN AMD_CONFIG_PARAMS *StdHeader
1106 AGESA_STATUS IgnoredSts;
1107 SOCKET_DIE_TO_NODE_MAP pSocketDieMap;
1108 LOCATE_HEAP_PTR SocketDieHeapDataBlock;
1109 CPU_SPECIFIC_SERVICES *FamilyServices;
1110 CORE_PAIR_MAP *CorePairMap;
1111 COMPUTE_UNIT_MAPPING Result;
1113 // Invalid mapping, unless we find one.
1114 Result = MaxComputeUnitMapping;
1116 IdentifyCore (StdHeader, &Socket, &Module, &CurrentCore, &IgnoredSts);
1117 GetCpuServicesOfCurrentCore ((const CPU_SPECIFIC_SERVICES **)&FamilyServices, StdHeader);
1118 ASSERT (FamilyServices != NULL);
1120 // Get data block from heap
1121 SocketDieHeapDataBlock.BufferHandle = SOCKET_DIE_MAP_HANDLE;
1122 IgnoredSts = HeapLocateBuffer (&SocketDieHeapDataBlock, StdHeader);
1123 pSocketDieMap = (SOCKET_DIE_TO_NODE_MAP)SocketDieHeapDataBlock.BufferPtr;
1124 ASSERT ((pSocketDieMap != NULL) && (IgnoredSts == AGESA_SUCCESS));
1125 // Current Core's socket, module must be present.
1126 ASSERT ((*pSocketDieMap)[Socket][Module].Node != 0xFF);
1128 // Process compute unit info
1129 Enabled = (*pSocketDieMap)[Socket][Module].EnabledComputeUnits;
1130 DualCore = (*pSocketDieMap)[Socket][Module].DualCoreComputeUnits;
1131 CorePairMap = FamilyServices->CorePairMap;
1132 if ((Enabled != 0) && (CorePairMap != NULL)) {
1133 while (CorePairMap->Enabled != 0xFF) {
1134 if ((Enabled == CorePairMap->Enabled) && (DualCore == CorePairMap->DualCore)) {
1139 // The assert is for finding a processor configured in a way the core pair map doesn't support.
1140 ASSERT (CorePairMap->Enabled != 0xFF);
1141 Result = CorePairMap->Mapping;
1143 // Families that don't have compute units act as though each core is in its own compute unit
1144 // and all cores are primary
1145 Result = AllCoresMapping;
1150 /*---------------------------------------------------------------------------------------*/
1152 * Is current core the primary core of its compute unit?
1154 * Get the mapping algorithm and the current core number. Selecting First/Last ordering for
1155 * primary @b ASSUMES cores are launched in ascending core number order.
1157 * @param[in] Selector Select whether first or last core has the primary core role.
1158 * @param[in] StdHeader Header for library and services
1160 * @retval TRUE This is the primary core of a compute unit.
1161 * @retval FALSE This is the second shared core of a compute unit.
1166 IN COMPUTE_UNIT_PRIMARY_SELECTOR Selector,
1167 IN AMD_CONFIG_PARAMS *StdHeader
1174 AGESA_STATUS IgnoredSts;
1176 IdentifyCore (StdHeader, &Socket, &Module, &CurrentCore, &IgnoredSts);
1179 switch (GetComputeUnitMapping (StdHeader)) {
1180 case AllCoresMapping:
1181 // All cores are primaries
1184 case EvenCoresMapping:
1185 // Even core numbers are first to execute, odd cores are last to execute
1186 if (Selector == FirstCoreIsComputeUnitPrimary) {
1187 Result = (BOOLEAN) ((CurrentCore & 1) == 0);
1189 Result = (BOOLEAN) ((CurrentCore & 1) != 0);
1198 /*---------------------------------------------------------------------------------------*/
1200 * Are the two specified cores shared in a compute unit?
1202 * Look up the compute unit values for the current core's socket/module and find the matching
1203 * core pair map item. This will tell us how to determine the core's status.
1205 * @param[in] Socket The processor in this socket is to be checked
1206 * @param[in] Module The processor in this module is to be checked
1207 * @param[in] CoreA One of the two cores to check
1208 * @param[in] CoreB The other core to be checked
1209 * @param[in] StdHeader Header for library and services
1211 * @retval TRUE The cores are in the same compute unit.
1212 * @retval FALSE The cores are not in the same compute unit, or the processor does
1213 * not have compute units.
1222 IN AMD_CONFIG_PARAMS *StdHeader
1228 switch (GetComputeUnitMapping (StdHeader)) {
1229 case AllCoresMapping:
1230 // No cores are sharing a compute unit
1233 case EvenCoresMapping:
1234 // Even core numbers are paired with odd core numbers, n with n + 1
1235 if ((CoreA & 1) == 0) {
1236 Result = (BOOLEAN) (CoreA == (CoreB - 1));
1238 Result = (BOOLEAN) (CoreA == (CoreB + 1));
1247 /*---------------------------------------------------------------------------------------*/
1250 * This routine programs the registers necessary to get the PCI MMIO mechanism
1251 * up and functioning.
1253 * @param[in] StdHeader Pointer to structure containing the function call
1254 * whose parameter structure is to be created, the
1255 * allocation method, and a pointer to the newly
1256 * created structure.
1261 IN AMD_CONFIG_PARAMS *StdHeader
1265 UINT64 LocalMsrRegister;
1267 // Make sure that Standard header is valid
1268 ASSERT (StdHeader != NULL);
1270 if ((UserOptions.CfgPciMmioAddress != 0) && (UserOptions.CfgPciMmioSize != 0)) {
1271 EncodedSize = LibAmdBitScanForward (UserOptions.CfgPciMmioSize);
1272 LocalMsrRegister = ((UserOptions.CfgPciMmioAddress | BIT0) | (EncodedSize << 2));
1273 LibAmdMsrWrite (MSR_MMIO_Cfg_Base, &LocalMsrRegister, StdHeader);