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: 36208 $ @e \$Date: 2010-08-13 22:55:05 +0800 (Fri, 13 Aug 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.
44 * ***************************************************************************
48 /*----------------------------------------------------------------------------------------
49 * M O D U L E S U S E D
50 *----------------------------------------------------------------------------------------
57 #include "cpuRegisters.h"
58 #include "GeneralServices.h"
59 #include "cpuFamilyTranslation.h"
60 #include "cpuServices.h"
61 #include "heapManager.h"
62 #include "cpuApicUtilities.h"
65 RDATA_GROUP (G1_PEICC)
67 #define FILECODE PROC_CPU_CPUGENERALSERVICES_FILECODE
68 /*----------------------------------------------------------------------------------------
69 * D E F I N I T I O N S A N D M A C R O S
70 *----------------------------------------------------------------------------------------
72 extern OPTIONS_CONFIG_TOPOLOGY TopologyConfiguration;
73 extern BUILD_OPT_CFG UserOptions;
75 /*----------------------------------------------------------------------------------------
76 * T Y P E D E F S A N D S T R U C T U R E S
77 *----------------------------------------------------------------------------------------
80 /*----------------------------------------------------------------------------------------
81 * 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
82 *----------------------------------------------------------------------------------------
85 /*----------------------------------------------------------------------------------------
86 * E X P O R T E D F U N C T I O N S - External General Services API
87 *----------------------------------------------------------------------------------------
91 * Get a specified Core's APIC ID.
93 * Invoke corresponding Cpu Service for external user.
95 * @param[in,out] AmdParamApic Our interface struct
97 * @return The most severe status of any called service.
101 IN OUT AMD_APIC_PARAMS *AmdParamApic
104 AGESA_STATUS AgesaStatus;
106 AGESA_TESTPOINT (TpIfAmdGetApicIdEntry, &AmdParamApic->StdHeader);
107 AmdParamApic->StdHeader.HeapBasePtr = HeapGetBaseAddress (&AmdParamApic->StdHeader);
109 AmdParamApic->IsPresent = GetApicId (
110 &AmdParamApic->StdHeader,
111 AmdParamApic->Socket,
113 &AmdParamApic->ApicAddress,
117 AGESA_TESTPOINT (TpIfAmdGetApicIdExit, &AmdParamApic->StdHeader);
122 * Get Processor Module's PCI Config Space address.
124 * Invoke corresponding Cpu Service for external user.
126 * @param[in,out] AmdParamGetPci Our interface struct
128 * @return The most severe status of any called service.
132 IN OUT AMD_GET_PCI_PARAMS *AmdParamGetPci
135 AGESA_STATUS AgesaStatus;
137 AGESA_TESTPOINT (TpIfAmdGetPciAddressEntry, &AmdParamGetPci->StdHeader);
138 AmdParamGetPci->StdHeader.HeapBasePtr = HeapGetBaseAddress (&AmdParamGetPci->StdHeader);
140 AmdParamGetPci->IsPresent = GetPciAddress (
141 &AmdParamGetPci->StdHeader,
142 AmdParamGetPci->Socket,
143 AmdParamGetPci->Module,
144 &AmdParamGetPci->PciAddress,
148 AGESA_TESTPOINT (TpIfAmdGetPciAddressExit, &AmdParamGetPci->StdHeader);
153 * "Who am I" for the current running core.
155 * Invoke corresponding Cpu Service for external user.
157 * @param[in,out] AmdParamIdentify Our interface struct
159 * @return The most severe status of any called service.
163 IN OUT AMD_IDENTIFY_PARAMS *AmdParamIdentify
166 AGESA_STATUS AgesaStatus;
171 AGESA_TESTPOINT (TpIfAmdIdentifyCoreEntry, &AmdParamIdentify->StdHeader);
172 AmdParamIdentify->StdHeader.HeapBasePtr = HeapGetBaseAddress (&AmdParamIdentify->StdHeader);
175 &AmdParamIdentify->StdHeader,
181 AmdParamIdentify->Socket = (UINT8)Socket;
182 AmdParamIdentify->Module = (UINT8)Module;
183 AmdParamIdentify->Core = (UINT8)Core;
185 AGESA_TESTPOINT (TpIfAmdIdentifyCoreExit, &AmdParamIdentify->StdHeader);
189 /*----------------------------------------------------------------------------------------
190 * E X P O R T E D F U N C T I O N S - AGESA common General Services
191 *----------------------------------------------------------------------------------------
194 /*---------------------------------------------------------------------------------------*/
196 * Get a specified Core's APIC ID.
198 * Code sync: This calculation MUST match the assignment
199 * calculation done in LocalApicInitializationAtEarly function.
201 * @param[in] StdHeader Header for library and services.
202 * @param[in] Socket The socket in which the Core's Processor is installed.
203 * @param[in] Core The Core id.
204 * @param[out] ApicAddress The Core's APIC ID.
205 * @param[out] AgesaStatus Aggregates AGESA_STATUS for external interface, Always Succeeds.
207 * @retval TRUE The core is present, APIC Id valid
208 * @retval FALSE The core is not present, APIC Id not valid.
212 IN AMD_CONFIG_PARAMS *StdHeader,
215 OUT UINT8 *ApicAddress,
216 OUT AGESA_STATUS *AgesaStatus
224 if (GetActiveCoresInGivenSocket (Socket, &CoreCount, StdHeader)) {
225 if (Core < CoreCount) {
227 GetLocalApicIdForCore (Socket, Core, &ApicID, StdHeader);
228 *ApicAddress = (UINT8) ApicID;
233 *AgesaStatus = AGESA_SUCCESS;
238 /*---------------------------------------------------------------------------------------*/
240 * Get Processor Module's PCI Config Space address.
242 * @param[in] StdHeader Header for library and services.
243 * @param[in] Socket The Core's Socket.
244 * @param[in] Module The Module in that Processor
245 * @param[out] PciAddress The Processor's PCI Config Space address (Function 0, Register 0)
246 * @param[out] AgesaStatus Aggregates AGESA_STATUS for external interface, Always Succeeds.
248 * @retval TRUE The core is present, PCI Address valid
249 * @retval FALSE The core is not present, PCI Address not valid.
253 IN AMD_CONFIG_PARAMS *StdHeader,
256 OUT PCI_ADDR *PciAddress,
257 OUT AGESA_STATUS *AgesaStatus
263 ASSERT (Socket < MAX_SOCKETS);
264 ASSERT (Module < MAX_DIES);
268 *AgesaStatus = AGESA_SUCCESS;
270 if (GetNodeId (Socket, Module, &Node, StdHeader)) {
271 // socket is populated
272 PciAddress->AddressValue = MAKE_SBDFO (0, 0, 24, 0, 0);
273 PciAddress->Address.Device = PciAddress->Address.Device + Node;
275 // socket is not populated
276 PciAddress->AddressValue = ILLEGAL_SBDFO;
282 /*---------------------------------------------------------------------------------------*/
284 * "Who am I" for the current running core.
286 * @param[in] StdHeader Header for library and services.
287 * @param[out] Socket The current Core's Socket
288 * @param[out] Module The current Core's Processor Module
289 * @param[out] Core The current Core's core id.
290 * @param[out] AgesaStatus Aggregates AGESA_STATUS for external interface, Always Succeeds.
295 IN AMD_CONFIG_PARAMS *StdHeader,
299 OUT AGESA_STATUS *AgesaStatus
302 AP_MAIL_INFO ApMailboxInfo;
306 *AgesaStatus = AGESA_SUCCESS;
308 GetApMailbox (&ApMailboxInfo.Info, StdHeader);
309 ASSERT (ApMailboxInfo.Fields.Socket < MAX_SOCKETS);
310 ASSERT (ApMailboxInfo.Fields.Module < MAX_DIES);
311 *Socket = (UINT8)ApMailboxInfo.Fields.Socket;
312 *Module = (UINT8)ApMailboxInfo.Fields.Module;
315 GetCurrentCore (&CurrentCore, StdHeader);
316 *Core = (UINT8)CurrentCore;
320 /*----------------------------------------------------------------------------------------
321 * E X P O R T E D F U N C T I O N S - cpu component General Services
322 *----------------------------------------------------------------------------------------
325 /*---------------------------------------------------------------------------------------*/
327 * Get the current Platform's number of Sockets, regardless of how many are populated.
329 * The Options component can provide how many sockets are available in system.
330 * This can be used to avoid testing presence of Processors in Sockets which don't exist.
331 * The result can be one socket to the maximum possible sockets of any supported processor family.
332 * You cannot assume that all sockets contain a processor or that the sockets have processors
333 * installed in any particular order. Do not convert this number to a number of nodes.
335 * @return The number of available sockets for the platform.
339 GetPlatformNumberOfSockets ()
341 return TopologyConfiguration.PlatformNumberOfSockets;
344 /*---------------------------------------------------------------------------------------*/
346 * Get the number of Modules to check presence in each Processor.
348 * The Options component can provide how many modules need to be check for presence in each
349 * processor, regardless whether all, or any, processor have that many modules present on this boot.
350 * The result can be one module to the maximum possible modules of any supported processor family.
351 * You cannot assume that Modules are in any particular order, especially with respect to node id.
353 * @return The maximum number of modules in each processor.
357 GetPlatformNumberOfModules ()
359 return TopologyConfiguration.PlatformNumberOfModules;
362 /*---------------------------------------------------------------------------------------*/
364 * Is a processor present in Socket?
366 * Check to see if any possible module of the processor is present. This provides
367 * support for a few cases where a PCI address isn't needed, but code still needs to
370 * @param[in] Socket The socket which is being tested
371 * @param[in] StdHeader Header for library and services.
373 * @retval TRUE The socket has a processor installed
374 * @retval FALSE The socket is empty (or the processor is dead).
380 IN AMD_CONFIG_PARAMS *StdHeader
383 SOCKET_DIE_TO_NODE_MAP pSocketDieMap;
384 LOCATE_HEAP_PTR SocketDieHeapDataBlock;
389 ASSERT (Socket < MAX_SOCKETS);
391 SocketDieHeapDataBlock.BufferHandle = SOCKET_DIE_MAP_HANDLE;
393 // Get data block from heap
394 Status = HeapLocateBuffer (&SocketDieHeapDataBlock, StdHeader);
395 pSocketDieMap = (SOCKET_DIE_TO_NODE_MAP)SocketDieHeapDataBlock.BufferPtr;
396 ASSERT ((pSocketDieMap != NULL) && (Status == AGESA_SUCCESS));
397 for (Module = 0; Module < GetPlatformNumberOfModules (); Module++) {
398 if ((*pSocketDieMap)[Socket][Module].Node != 0xFF) {
406 /*---------------------------------------------------------------------------------------*/
408 * Provide the number of installed processors (not Nodes! and not Sockets!)
410 * Iterate over the Socket, Module to Node Map, counting the number of present nodes.
411 * Do not use this as a Node Count! Do not use this as the number of Sockets! (This
412 * is for APIC ID utilities.)
414 * @param[in] StdHeader Header for library and services.
416 * @return the number of processors installed
420 GetNumberOfProcessors (
421 IN AMD_CONFIG_PARAMS *StdHeader
424 SOCKET_DIE_TO_NODE_MAP pSocketDieMap;
425 LOCATE_HEAP_PTR SocketDieHeapDataBlock;
432 SocketDieHeapDataBlock.BufferHandle = SOCKET_DIE_MAP_HANDLE;
434 // Get data block from heap
435 Status = HeapLocateBuffer (&SocketDieHeapDataBlock, StdHeader);
436 pSocketDieMap = (SOCKET_DIE_TO_NODE_MAP)SocketDieHeapDataBlock.BufferPtr;
437 ASSERT ((pSocketDieMap != NULL) && (Status == AGESA_SUCCESS));
438 for (Socket = 0; Socket < GetPlatformNumberOfSockets (); Socket++) {
439 for (Module = 0; Module < GetPlatformNumberOfModules (); Module++) {
440 if ((*pSocketDieMap)[Socket][Module].Node != 0xFF) {
449 /*---------------------------------------------------------------------------------------*/
451 * For a specific Node, get its Socket and Module ids.
453 * If asking for the current running Node, read the mailbox socket, module. Specific Node,
454 * locate the Node to Socket/Module Map in heap, and return the ids, if present.
456 * @param[in] Node What Socket and Module is this Node?
457 * @param[out] Socket The Socket containing that Node.
458 * @param[out] Module The Processor Module of that Node.
459 * @param[in] StdHeader Header for library and services.
461 * @retval TRUE Node is present, Socket, Module are valid.
462 * @retval FALSE Node is not present, why do you ask?
465 GetSocketModuleOfNode (
469 IN AMD_CONFIG_PARAMS *StdHeader
472 NODE_TO_SOCKET_DIE_MAP pNodeMap;
473 LOCATE_HEAP_PTR SocketDieHeapDataBlock;
479 ASSERT (Node < MAX_NODES);
482 SocketDieHeapDataBlock.BufferHandle = NODE_ID_MAP_HANDLE;
483 Status = HeapLocateBuffer (&SocketDieHeapDataBlock, StdHeader);
484 pNodeMap = (NODE_TO_SOCKET_DIE_MAP)SocketDieHeapDataBlock.BufferPtr;
485 ASSERT ((pNodeMap != NULL) && (Status == AGESA_SUCCESS));
486 *Socket = (*pNodeMap)[Node].Socket;
487 *Module = (*pNodeMap)[Node].Die;
488 if ((*pNodeMap)[Node].Socket != 0xFF) {
494 /*---------------------------------------------------------------------------------------*/
496 * Get the current core's Processor APIC Index.
498 * The Processor APIC Index is the position of the current processor in the APIC id
499 * assignment. Processors are ordered in node id order. This is not the same, however,
500 * as the node id of the current socket and module or the current socket id.
502 * @param[in] Node The current desired core's node id (usually the current core).
503 * @param[in] StdHeader Header for library and services.
505 * @return Processor APIC Index
509 GetProcessorApicIndex (
511 IN AMD_CONFIG_PARAMS *StdHeader
514 UINT32 ProcessorApicIndex;
515 UINT32 PreviousSocket;
516 UINT32 CurrentSocket;
520 ASSERT (Node < MAX_NODES);
522 // Calculate total APIC devices up to Current Node, Core.
523 ProcessorApicIndex = 0;
524 PreviousSocket = 0xFF;
525 for (i = 0; i < (Node + 1); i++) {
526 GetSocketModuleOfNode (i, &CurrentSocket, &Ignored, StdHeader);
527 if (CurrentSocket != PreviousSocket) {
528 ProcessorApicIndex++;
529 PreviousSocket = CurrentSocket;
532 // Convert to Index (zero based) from count (one based).
533 ProcessorApicIndex--;
534 return ProcessorApicIndex;
537 /*---------------------------------------------------------------------------------------*/
539 * Returns current node number
541 * @param[out] Node This Core's Node id
542 * @param[in] StdHeader Header for library and services.
548 IN AMD_CONFIG_PARAMS *StdHeader
551 AP_MAIL_INFO ApMailboxInfo;
553 // Get the Node Id from the Mailbox.
554 GetApMailbox (&ApMailboxInfo.Info, StdHeader);
555 ASSERT (ApMailboxInfo.Fields.Node < MAX_NODES);
556 *Node = ApMailboxInfo.Fields.Node;
559 /*---------------------------------------------------------------------------------------*/
561 * Writes to all nodes on the executing core's socket.
563 * @param[in] PciAddress The Function and Register to update
564 * @param[in] Mask The bitwise AND mask to apply to the current register value
565 * @param[in] Data The bitwise OR mask to apply to the current register value
566 * @param[in] StdHeader Header for library and services.
570 ModifyCurrentSocketPci (
571 IN PCI_ADDR *PciAddress,
574 IN AMD_CONFIG_PARAMS *StdHeader
581 AGESA_STATUS AgesaStatus;
584 IdentifyCore (StdHeader, &Socket, &Module, &Core, &AgesaStatus);
586 for (Module = 0; Module < (UINT8)GetPlatformNumberOfModules (); Module++) {
587 if (GetPciAddress (StdHeader, Socket, Module, &Reg, &AgesaStatus)) {
588 Reg.Address.Function = PciAddress->Address.Function;
589 Reg.Address.Register = PciAddress->Address.Register;
590 LibAmdPciRead (AccessWidth32, Reg, &PciReg, StdHeader);
593 LibAmdPciWrite (AccessWidth32, Reg, &PciReg, StdHeader);
598 /*---------------------------------------------------------------------------------------*/
600 * Returns Total number of active cores in the current socket
602 * @param[out] CoreCount The cores in this processor.
603 * @param[in] StdHeader Header for library and services.
607 GetActiveCoresInCurrentSocket (
608 OUT UINT32 *CoreCount,
609 IN AMD_CONFIG_PARAMS *StdHeader
612 CPUID_DATA CpuidDataStruct;
613 UINT32 TotalCoresCount;
615 LibAmdCpuidRead (AMD_CPUID_ASIZE_PCCOUNT, &CpuidDataStruct, StdHeader);
616 TotalCoresCount = (CpuidDataStruct.ECX_Reg & 0x000000FF) + 1;
617 *CoreCount = TotalCoresCount;
620 /*---------------------------------------------------------------------------------------*/
622 * Provides the Total number of active cores in the current core's node.
624 * @param[in] StdHeader Header for library and services.
626 * @return The current node core count
629 GetActiveCoresInCurrentModule (
630 IN AMD_CONFIG_PARAMS *StdHeader
638 UINT32 ProcessorCoreCount;
639 AGESA_STATUS AgesaStatus;
641 ProcessorCoreCount = 0;
643 IdentifyCore (StdHeader, &Socket, &Module, &Core, &AgesaStatus);
644 if (GetGivenModuleCoreRange (Socket, Module, &LowCore, &HighCore, StdHeader)) {
645 ProcessorCoreCount = ((HighCore - LowCore) + 1);
647 return ProcessorCoreCount;
651 * Provide the number of compute units on current module.
654 * @param[in] StdHeader Header for library and services.
656 * @return The current compute unit counts.
660 GetNumberOfCompUnitsInCurrentModule (
661 IN AMD_CONFIG_PARAMS *StdHeader
667 UINT32 ComputeUnitCount;
669 AGESA_STATUS IgnoredSts;
670 LOCATE_HEAP_PTR SocketDieHeapDataBlock;
671 SOCKET_DIE_TO_NODE_MAP pSocketDieMap;
673 ComputeUnitCount = 0;
675 ASSERT ((GetComputeUnitMapping (StdHeader) == AllCoresMapping) ||
676 (GetComputeUnitMapping (StdHeader) == EvenCoresMapping));
678 IdentifyCore (StdHeader, &Socket, &Module, &CurrentCore, &IgnoredSts);
679 // Get data block from heap
680 SocketDieHeapDataBlock.BufferHandle = SOCKET_DIE_MAP_HANDLE;
681 IgnoredSts = HeapLocateBuffer (&SocketDieHeapDataBlock, StdHeader);
682 pSocketDieMap = (SOCKET_DIE_TO_NODE_MAP)SocketDieHeapDataBlock.BufferPtr;
683 ASSERT ((pSocketDieMap != NULL) && (IgnoredSts == AGESA_SUCCESS));
684 // Current Core's socket, module must be present.
685 ASSERT ((*pSocketDieMap)[Socket][Module].Node != 0xFF);
686 // Process compute unit info
687 Enabled = (*pSocketDieMap)[Socket][Module].EnabledComputeUnits;
689 while (Enabled > 0) {
690 if ((Enabled & 0x1) != 0) {
696 return ComputeUnitCount;
699 /*---------------------------------------------------------------------------------------*/
701 * Provides the Total number of active cores in the given socket.
703 * @param[in] Socket Get a core count for the processor in this socket.
704 * @param[out] CoreCount Its core count
705 * @param[in] StdHeader Header for library and services.
707 * @retval TRUE A processor is present in the Socket and the CoreCount is valid.
708 * @retval FALSE The Socket does not have a Processor
711 GetActiveCoresInGivenSocket (
713 OUT UINT32 *CoreCount,
714 IN AMD_CONFIG_PARAMS *StdHeader
720 UINT32 ProcessorCoreCount;
724 ProcessorCoreCount = 0;
726 for (Module = 0; Module < GetPlatformNumberOfModules (); Module++) {
727 if (GetGivenModuleCoreRange (Socket, Module, &LowCore, &HighCore, StdHeader)) {
728 ProcessorCoreCount = ProcessorCoreCount + ((HighCore - LowCore) + 1);
734 *CoreCount = ProcessorCoreCount;
738 /*---------------------------------------------------------------------------------------*/
740 * Provides the range of Cores in a Processor which are in a Module.
742 * Cores are named uniquely in a processor, 0 to TotalCores. Any module in the processor has
743 * a set of those cores, named from LowCore to HighCore.
745 * @param[in] Socket Get a core range for the processor in this socket.
746 * @param[in] Module Get a core range for this Module in the processor.
747 * @param[out] LowCore The lowest Processor Core in the Module.
748 * @param[out] HighCore The highest Processor Core in the Module.
749 * @param[in] StdHeader Header for library and services.
751 * @retval TRUE A processor is present in the Socket and the Core Range is valid.
752 * @retval FALSE The Socket does not have a Processor
755 GetGivenModuleCoreRange (
759 OUT UINT32 *HighCore,
760 IN AMD_CONFIG_PARAMS *StdHeader
763 SOCKET_DIE_TO_NODE_MAP pSocketDieMap;
764 LOCATE_HEAP_PTR SocketDieHeapDataBlock;
768 ASSERT (Socket < MAX_SOCKETS);
769 ASSERT (Module < MAX_DIES);
771 SocketDieHeapDataBlock.BufferHandle = SOCKET_DIE_MAP_HANDLE;
773 // Get data block from heap
774 Status = HeapLocateBuffer (&SocketDieHeapDataBlock, StdHeader);
775 pSocketDieMap = (SOCKET_DIE_TO_NODE_MAP)SocketDieHeapDataBlock.BufferPtr;
776 ASSERT ((pSocketDieMap != NULL) && (Status == AGESA_SUCCESS));
777 *LowCore = (*pSocketDieMap)[Socket][Module].LowCore;
778 *HighCore = (*pSocketDieMap)[Socket][Module].HighCore;
779 if ((*pSocketDieMap)[Socket][Module].Node != 0xFF) {
785 /*---------------------------------------------------------------------------------------*/
787 * Returns the current running core number.
789 * @param[out] Core The core id.
790 * @param[in] StdHeader Header for library and services.
796 IN AMD_CONFIG_PARAMS *StdHeader
799 CPUID_DATA CpuidDataStruct;
801 UINT32 ApicIdCoreIdSize;
802 CORE_ID_POSITION InitApicIdCpuIdLo;
803 CPU_SPECIFIC_SERVICES *FamilyServices;
805 GetCpuServicesOfCurrentCore ((const CPU_SPECIFIC_SERVICES **)&FamilyServices, StdHeader);
806 ASSERT (FamilyServices != NULL);
808 // Read CPUID ebx[31:24] to get initial APICID
809 LibAmdCpuidRead (AMD_CPUID_APICID_LPC_BID, &CpuidDataStruct, StdHeader);
810 LocalApicId = (CpuidDataStruct.EBX_Reg & 0xFF000000) >> 24;
812 // Find the core ID size.
813 LibAmdCpuidRead (AMD_CPUID_ASIZE_PCCOUNT, &CpuidDataStruct, StdHeader);
814 ApicIdCoreIdSize = (CpuidDataStruct.ECX_Reg & 0x0000F000) >> 12;
816 InitApicIdCpuIdLo = FamilyServices->CoreIdPositionInInitialApicId (FamilyServices, StdHeader);
817 ASSERT (InitApicIdCpuIdLo < CoreIdPositionMax);
819 // Now extract the core ID from the Apic ID by right justifying the id and masking off non-core Id bits.
820 *Core = ((LocalApicId >> ((1 - (UINT32)InitApicIdCpuIdLo) * (MAX_CORE_ID_SIZE - ApicIdCoreIdSize))) &
821 (MAX_CORE_ID_MASK >> (MAX_CORE_ID_SIZE - ApicIdCoreIdSize)));
824 /*---------------------------------------------------------------------------------------*/
826 * Returns current node, and core number.
828 * @param[out] Node The node id of the current core's node.
829 * @param[out] Core The core id if the current core.
830 * @param[in] StdHeader Config handle for library and services.
834 GetCurrentNodeAndCore (
837 IN AMD_CONFIG_PARAMS *StdHeader
841 GetCurrentNodeNum (Node, StdHeader);
844 GetCurrentCore (Core, StdHeader);
847 /*---------------------------------------------------------------------------------------*/
849 * Is the current core a primary core of it's node?
851 * @param[in] StdHeader Config handle for library and services.
853 * @retval TRUE Is Primary Core
854 * @retval FALSE Is not Primary Core
858 IsCurrentCorePrimary (
859 IN AMD_CONFIG_PARAMS *StdHeader
868 AGESA_STATUS IgnoredSts;
872 IdentifyCore (StdHeader, &Socket, &Module, &Core, &IgnoredSts);
873 GetGivenModuleCoreRange (Socket, Module, &PrimaryCore, &IgnoredCore, StdHeader);
874 if (Core == PrimaryCore) {
881 /*---------------------------------------------------------------------------------------*/
883 * Returns node id based on SocketId and ModuleId.
885 * @param[in] SocketId The socket to look up
886 * @param[in] ModuleId The module in that socket
887 * @param[out] NodeId Provide the corresponding Node Id.
888 * @param[in] StdHeader Handle of Header for calling lib functions and services.
890 * @retval TRUE The socket is populated
891 * @retval FALSE The socket is not populated
899 IN AMD_CONFIG_PARAMS *StdHeader
902 SOCKET_DIE_TO_NODE_MAP pSocketDieMap;
903 LOCATE_HEAP_PTR SocketDieHeapDataBlock;
908 SocketDieHeapDataBlock.BufferHandle = SOCKET_DIE_MAP_HANDLE;
910 // Get data block from heap
911 Status = HeapLocateBuffer (&SocketDieHeapDataBlock, StdHeader);
912 pSocketDieMap = (SOCKET_DIE_TO_NODE_MAP)SocketDieHeapDataBlock.BufferPtr;
913 ASSERT ((pSocketDieMap != NULL) && (Status == AGESA_SUCCESS));
914 *NodeId = (*pSocketDieMap)[SocketId][ModuleId].Node;
915 if ((*pSocketDieMap)[SocketId][ModuleId].Node != 0xFF) {
921 /*---------------------------------------------------------------------------------------*/
923 * Get the cached AP Mailbox Info if available, or read the info from the hardware.
925 * Locate the known AP Mailbox Info Cache buffer in this core's local heap. If it
926 * doesn't exist, read the hardware to get the info.
927 * This routine gets the main AP mailbox, not the system degree.
929 * @param[out] ApMailboxInfo Provide the info in this AP core's mailbox
930 * @param[in] StdHeader Config handle for library and services.
935 OUT UINT32 *ApMailboxInfo,
936 IN AMD_CONFIG_PARAMS *StdHeader
939 AGESA_STATUS Ignored;
940 LOCATE_HEAP_PTR LocalApMailboxCache;
941 CPU_SPECIFIC_SERVICES *FamilyServices;
942 AP_MAILBOXES ApMailboxes;
945 IamBsp = IsBsp (StdHeader, &Ignored);
946 LocalApMailboxCache.BufferHandle = LOCAL_AP_MAIL_BOX_CACHE_HANDLE;
947 if (((StdHeader->HeapStatus == HEAP_LOCAL_CACHE) || IamBsp) &&
948 (HeapLocateBuffer (&LocalApMailboxCache, StdHeader) == AGESA_SUCCESS)) {
949 // If during HEAP_LOCAL_CACHE stage, we always try to get ApMailbox from heap
950 // If we're not in HEAP_LOCAL_CACHE stage, only BSP can get ApMailbox from heap
951 *ApMailboxInfo = ((AP_MAILBOXES *) LocalApMailboxCache.BufferPtr)->ApMailInfo.Info;
952 } else if (!IamBsp) {
953 // If this is an AP, the hardware register should be good.
954 GetCpuServicesOfCurrentCore ((const CPU_SPECIFIC_SERVICES **)&FamilyServices, StdHeader);
955 ASSERT (FamilyServices != NULL);
956 FamilyServices->GetApMailboxFromHardware (FamilyServices, &ApMailboxes, StdHeader);
957 *ApMailboxInfo = ApMailboxes.ApMailInfo.Info;
959 // This is the BSC. The hardware mailbox has not been set up yet.
964 /*---------------------------------------------------------------------------------------*/
966 * Cache the Ap Mailbox info in our local heap for later use.
968 * This enables us to use the info even after the mailbox register is initialized
969 * with operational values. Get all the AP mailboxes and keep them in one buffer.
971 * @param[in] StdHeader Config handle for library and services.
976 IN AMD_CONFIG_PARAMS *StdHeader
979 ALLOCATE_HEAP_PARAMS AllocHeapParams;
980 AP_MAILBOXES ApMailboxes;
981 CPU_SPECIFIC_SERVICES *FamilyServices;
983 GetCpuServicesOfCurrentCore ((const CPU_SPECIFIC_SERVICES **)&FamilyServices, StdHeader);
984 ASSERT (FamilyServices != NULL);
986 // Get mailbox from hardware.
987 FamilyServices->GetApMailboxFromHardware (FamilyServices, &ApMailboxes, StdHeader);
989 // Allocate heap for the info
990 AllocHeapParams.RequestedBufferSize = sizeof (AP_MAILBOXES);
991 AllocHeapParams.BufferHandle = LOCAL_AP_MAIL_BOX_CACHE_HANDLE;
992 AllocHeapParams.Persist = HEAP_SYSTEM_MEM;
993 if (HeapAllocateBuffer (&AllocHeapParams, StdHeader) == AGESA_SUCCESS) {
994 *(AP_MAILBOXES *)AllocHeapParams.BufferPtr = ApMailboxes;
998 /*---------------------------------------------------------------------------------------*/
1000 * Compute the degree of the system.
1002 * The degree of a system is the maximum degree of any node. The degree of a node is the
1003 * number of nodes to which it is directly connected (not considering width or redundant
1006 * @param[in] StdHeader Config handle for library and services.
1011 IN AMD_CONFIG_PARAMS *StdHeader
1014 AP_MAILBOXES *ApMailboxes;
1015 LOCATE_HEAP_PTR LocalApMailboxCache;
1016 AGESA_STATUS Status;
1018 // Get data block from heap
1019 LocalApMailboxCache.BufferHandle = LOCAL_AP_MAIL_BOX_CACHE_HANDLE;
1020 Status = HeapLocateBuffer (&LocalApMailboxCache, StdHeader);
1021 // non-Success handled by ASSERT not NULL below.
1022 ApMailboxes = (AP_MAILBOXES *)LocalApMailboxCache.BufferPtr;
1023 ASSERT ((ApMailboxes != NULL) && (Status == AGESA_SUCCESS));
1024 return ApMailboxes->ApMailExtInfo.Fields.SystemDegree;
1027 /*---------------------------------------------------------------------------------------*/
1029 * Spins until the number of microseconds specified have
1030 * expired regardless of CPU operational frequency.
1032 * @param[in] Microseconds Wait time in microseconds
1033 * @param[in] StdHeader Header for library and services
1038 IN UINT32 Microseconds,
1039 IN AMD_CONFIG_PARAMS *StdHeader
1042 UINT32 TscRateInMhz;
1043 UINT64 NumberOfTicks;
1046 CPU_SPECIFIC_SERVICES *FamilySpecificServices;
1048 LibAmdMsrRead (TSC, &InitialTsc, StdHeader);
1049 GetCpuServicesOfCurrentCore ((const CPU_SPECIFIC_SERVICES **)&FamilySpecificServices, StdHeader);
1050 FamilySpecificServices->GetTscRate (FamilySpecificServices, &TscRateInMhz, StdHeader);
1051 NumberOfTicks = Microseconds * TscRateInMhz;
1053 LibAmdMsrRead (TSC, &CurrentTsc, StdHeader);
1054 } while ((CurrentTsc - InitialTsc) < NumberOfTicks);
1057 /*---------------------------------------------------------------------------------------*/
1059 * A boolean function determine executed CPU is BSP core.
1061 * @param[in,out] StdHeader Header for library and services
1062 * @param[out] AgesaStatus Aggregates AGESA_STATUS for external interface, Always Succeeds.
1067 IN OUT AMD_CONFIG_PARAMS *StdHeader,
1068 OUT AGESA_STATUS *AgesaStatus
1074 *AgesaStatus = AGESA_SUCCESS;
1076 // Read APIC_BASE register (0x1B), bit[8] returns 1 for BSP
1077 LibAmdMsrRead (MSR_APIC_BAR, &MsrData, StdHeader);
1078 if ((MsrData & BIT8) != 0 ) {
1086 /*---------------------------------------------------------------------------------------*/
1088 * Get the compute unit mapping algorithm.
1090 * Look up the compute unit values for the current core's socket/module and find the matching
1091 * core pair map item. This will tell us how to determine the core's status.
1093 * @param[in] StdHeader Header for library and services
1095 * @retval AllCoresMapping Each core is in a compute unit of its own.
1096 * @retval EvenCoresMapping Even/Odd pairs of cores are in each compute unit.
1098 COMPUTE_UNIT_MAPPING
1099 GetComputeUnitMapping (
1100 IN AMD_CONFIG_PARAMS *StdHeader
1108 AGESA_STATUS IgnoredSts;
1109 SOCKET_DIE_TO_NODE_MAP pSocketDieMap;
1110 LOCATE_HEAP_PTR SocketDieHeapDataBlock;
1111 CPU_SPECIFIC_SERVICES *FamilyServices;
1112 CORE_PAIR_MAP *CorePairMap;
1113 COMPUTE_UNIT_MAPPING Result;
1115 // Invalid mapping, unless we find one.
1116 Result = MaxComputeUnitMapping;
1118 IdentifyCore (StdHeader, &Socket, &Module, &CurrentCore, &IgnoredSts);
1119 GetCpuServicesOfCurrentCore ((const CPU_SPECIFIC_SERVICES **)&FamilyServices, StdHeader);
1120 ASSERT (FamilyServices != NULL);
1122 // Get data block from heap
1123 SocketDieHeapDataBlock.BufferHandle = SOCKET_DIE_MAP_HANDLE;
1124 IgnoredSts = HeapLocateBuffer (&SocketDieHeapDataBlock, StdHeader);
1125 pSocketDieMap = (SOCKET_DIE_TO_NODE_MAP)SocketDieHeapDataBlock.BufferPtr;
1126 ASSERT ((pSocketDieMap != NULL) && (IgnoredSts == AGESA_SUCCESS));
1127 // Current Core's socket, module must be present.
1128 ASSERT ((*pSocketDieMap)[Socket][Module].Node != 0xFF);
1130 // Process compute unit info
1131 Enabled = (*pSocketDieMap)[Socket][Module].EnabledComputeUnits;
1132 DualCore = (*pSocketDieMap)[Socket][Module].DualCoreComputeUnits;
1133 CorePairMap = FamilyServices->CorePairMap;
1134 if ((Enabled != 0) && (CorePairMap != NULL)) {
1135 while (CorePairMap->Enabled != 0xFF) {
1136 if ((Enabled == CorePairMap->Enabled) && (DualCore == CorePairMap->DualCore)) {
1141 // The assert is for finding a processor configured in a way the core pair map doesn't support.
1142 ASSERT (CorePairMap->Enabled != 0xFF);
1143 Result = CorePairMap->Mapping;
1145 // Families that don't have compute units act as though each core is in its own compute unit
1146 // and all cores are primary
1147 Result = AllCoresMapping;
1152 /*---------------------------------------------------------------------------------------*/
1154 * Is current core the primary core of its compute unit?
1156 * Get the mapping algorithm and the current core number. Selecting First/Last ordering for
1157 * primary @b ASSUMES cores are launched in ascending core number order.
1159 * @param[in] Selector Select whether first or last core has the primary core role.
1160 * @param[in] StdHeader Header for library and services
1162 * @retval TRUE This is the primary core of a compute unit.
1163 * @retval FALSE This is the second shared core of a compute unit.
1168 IN COMPUTE_UNIT_PRIMARY_SELECTOR Selector,
1169 IN AMD_CONFIG_PARAMS *StdHeader
1176 AGESA_STATUS IgnoredSts;
1178 IdentifyCore (StdHeader, &Socket, &Module, &CurrentCore, &IgnoredSts);
1181 switch (GetComputeUnitMapping (StdHeader)) {
1182 case AllCoresMapping:
1183 // All cores are primaries
1186 case EvenCoresMapping:
1187 // Even core numbers are first to execute, odd cores are last to execute
1188 if (Selector == FirstCoreIsComputeUnitPrimary) {
1189 Result = (BOOLEAN) ((CurrentCore & 1) == 0);
1191 Result = (BOOLEAN) ((CurrentCore & 1) != 0);
1200 /*---------------------------------------------------------------------------------------*/
1202 * Are the two specified cores shared in a compute unit?
1204 * Look up the compute unit values for the current core's socket/module and find the matching
1205 * core pair map item. This will tell us how to determine the core's status.
1207 * @param[in] Socket The processor in this socket is to be checked
1208 * @param[in] Module The processor in this module is to be checked
1209 * @param[in] CoreA One of the two cores to check
1210 * @param[in] CoreB The other core to be checked
1211 * @param[in] StdHeader Header for library and services
1213 * @retval TRUE The cores are in the same compute unit.
1214 * @retval FALSE The cores are not in the same compute unit, or the processor does
1215 * not have compute units.
1224 IN AMD_CONFIG_PARAMS *StdHeader
1230 switch (GetComputeUnitMapping (StdHeader)) {
1231 case AllCoresMapping:
1232 // No cores are sharing a compute unit
1235 case EvenCoresMapping:
1236 // Even core numbers are paired with odd core numbers, n with n + 1
1237 if ((CoreA & 1) == 0) {
1238 Result = (BOOLEAN) (CoreA == (CoreB - 1));
1240 Result = (BOOLEAN) (CoreA == (CoreB + 1));
1249 /*---------------------------------------------------------------------------------------*/
1252 * This routine programs the registers necessary to get the PCI MMIO mechanism
1253 * up and functioning.
1255 * @param[in] StdHeader Pointer to structure containing the function call
1256 * whose parameter structure is to be created, the
1257 * allocation method, and a pointer to the newly
1258 * created structure.
1263 IN AMD_CONFIG_PARAMS *StdHeader
1269 // Make sure that Standard header is valid
1270 ASSERT (StdHeader != NULL);
1272 if ((UserOptions.CfgPciMmioAddress != 0) && (UserOptions.CfgPciMmioSize != 0)) {
1273 EncodedSize = LibAmdBitScanForward (UserOptions.CfgPciMmioSize);
1274 MsrReg = ((UserOptions.CfgPciMmioAddress | BIT0) | (EncodedSize << 2));
1275 LibAmdMsrWrite (MSR_MMIO_Cfg_Base, &MsrReg, StdHeader);