5 * External Interface implementation, general purpose features.
7 * Contains routines for implementing the interface to the client BIOS. This file
8 * includes the interface support which is not removed with various build options.
10 * @xrefitem bom "File Content Label" "Release Content"
12 * @e sub-project: HyperTransport
13 * @e \$Revision: 56279 $ @e \$Date: 2011-07-11 13:11:28 -0600 (Mon, 11 Jul 2011) $
17 *****************************************************************************
19 * Copyright (C) 2012 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 * ***************************************************************************
49 *----------------------------------------------------------------------------
52 *----------------------------------------------------------------------------
59 #include "OptionMultiSocket.h"
63 #include "htInterface.h"
64 #include "htInterfaceGeneral.h"
66 #include "cpuServices.h"
67 #include "cpuFeatures.h"
68 #include "heapManager.h"
73 #define FILECODE PROC_HT_HTINTERFACEGENERAL_FILECODE
74 /*----------------------------------------------------------------------------
75 * DEFINITIONS AND MACROS
77 *----------------------------------------------------------------------------
79 extern OPTION_MULTISOCKET_CONFIGURATION OptionMultiSocketConfiguration;
81 /*----------------------------------------------------------------------------
82 * TYPEDEFS AND STRUCTURES
84 *----------------------------------------------------------------------------
87 /*----------------------------------------------------------------------------
88 * PROTOTYPES OF LOCAL FUNCTIONS
90 *----------------------------------------------------------------------------
93 /*----------------------------------------------------------------------------
96 *----------------------------------------------------------------------------
99 /*----------------------------------------------------------------------------
102 *----------------------------------------------------------------------------
105 /*----------------------------------------------------------------------------------------*/
107 * Is PackageLink an Internal Link?
109 * This is a test for the logical link match codes in the user interface, not a test for
110 * the actual northbridge links.
112 * @param[in] PackageLink The link
114 * @retval TRUE This is an internal link
115 * @retval FALSE This is not an internal link
118 IsPackageLinkInternal (
122 return (BOOLEAN) ((PackageLink <= HT_LIST_MATCH_INTERNAL_LINK_2) && (PackageLink >= HT_LIST_MATCH_INTERNAL_LINK_0));
125 /*----------------------------------------------------------------------------------------*/
129 * @HtInterfaceMethod{::F_GET_IGNORE_LINK}
131 * This routine is called every time a coherent Link is found and then every time a
132 * non-coherent Link from a CPU is found. Any coherent or non-coherent Link from a
133 * CPU can be ignored and not used for discovery or initialization. Useful for
134 * connection based systems.
136 * @note not called for IO device to IO Device Links.
138 * @param[in] Node The Node on which this Link is located
139 * @param[in] Link The Link about to be initialized
140 * @param[in] NbIgnoreLinkList The northbridge default ignore link list
141 * @param[in] State the input data
143 * @retval MATCHED ignore this Link and skip it
144 * @retval POWERED_OFF ignore this link and power it off.
145 * @retval UNMATCHED initialize the Link normally
151 IN IGNORE_LINK *NbIgnoreLinkList,
156 FINAL_LINK_STATE Result;
161 ASSERT ((Node < MAX_NODES) && (Link < MAX_NODES));
165 Socket = State->HtInterface->GetSocketFromMap (Node, State);
166 PackageLink = State->Nb->GetPackageLink (Node, Link, State->Nb);
168 if (State->HtBlock->IgnoreLinkList != NULL) {
169 p = State->HtBlock->IgnoreLinkList;
170 while (p->Socket != HT_LIST_TERMINAL) {
171 if (((p->Socket == Socket) || (p->Socket == HT_LIST_MATCH_ANY)) &&
172 ((p->Link == PackageLink) ||
173 ((p->Link == HT_LIST_MATCH_ANY) && (!IsPackageLinkInternal (PackageLink))) ||
174 ((p->Link == HT_LIST_MATCH_INTERNAL_LINK) && (IsPackageLinkInternal (PackageLink))))) {
175 // Found a match return the desired link state.
176 ASSERT (Result < MaxFinalLinkState);
177 Result = p->LinkState;
185 // If there wasn't a match in the user interface, see if the northbridge provides one.
186 if (!IsFound && (NbIgnoreLinkList != NULL)) {
187 p = NbIgnoreLinkList;
188 while (p->Socket != HT_LIST_TERMINAL) {
189 if (((p->Socket == Socket) || (p->Socket == HT_LIST_MATCH_ANY)) &&
190 ((p->Link == PackageLink) ||
191 ((p->Link == HT_LIST_MATCH_ANY) && (!IsPackageLinkInternal (PackageLink))) ||
192 ((p->Link == HT_LIST_MATCH_INTERNAL_LINK) && (IsPackageLinkInternal (PackageLink))))) {
193 // Found a match return the desired link state.
194 ASSERT (Result < MaxFinalLinkState);
195 Result = p->LinkState;
205 /*----------------------------------------------------------------------------------------*/
207 * Get the Socket number for a given Node number.
209 * @HtInterfaceMethod{::F_GET_SOCKET_FROM_MAP}
213 * @param[in] Node The Node to translate
214 * @param[in] State reference to Node to socket map
216 * @return the socket id
227 ASSERT (State->NodeToSocketDieMap != NULL);
229 Socket = (*State->NodeToSocketDieMap)[Node].Socket;
233 /*----------------------------------------------------------------------------------------*/
235 * Get a new Socket Die to Node Map.
237 * @HtInterfaceMethod{::F_NEW_NODE_AND_SOCKET_TABLES}
239 * Put the Socket Die Table in heap with a known handle. Content will be generated as
240 * each node is discovered.
242 * @param[in,out] State global state
245 NewNodeAndSocketTables (
246 IN OUT STATE_DATA *State
251 ALLOCATE_HEAP_PARAMS AllocHeapParams;
253 // Allocate heap for the table
254 State->SocketDieToNodeMap = NULL;
255 AllocHeapParams.RequestedBufferSize = (((MAX_SOCKETS) * (MAX_DIES)) * sizeof (SOCKET_DIE_TO_NODE_ITEM));
256 AllocHeapParams.BufferHandle = SOCKET_DIE_MAP_HANDLE;
257 AllocHeapParams.Persist = HEAP_SYSTEM_MEM;
258 if (HeapAllocateBuffer (&AllocHeapParams, State->ConfigHandle) == AGESA_SUCCESS) {
259 State->SocketDieToNodeMap = (SOCKET_DIE_TO_NODE_MAP)AllocHeapParams.BufferPtr;
260 // Initialize shared data structures
261 for (i = 0; i < MAX_SOCKETS; i++) {
262 for (j = 0; j < MAX_DIES; j++) {
263 (*State->SocketDieToNodeMap)[i][j].Node = HT_LIST_TERMINAL;
264 (*State->SocketDieToNodeMap)[i][j].LowCore = HT_LIST_TERMINAL;
265 (*State->SocketDieToNodeMap)[i][j].HighCore = HT_LIST_TERMINAL;
269 // Allocate heap for the table
270 State->NodeToSocketDieMap = NULL;
271 AllocHeapParams.RequestedBufferSize = (MAX_NODES * sizeof (NODE_TO_SOCKET_DIE_ITEM));
272 AllocHeapParams.BufferHandle = NODE_ID_MAP_HANDLE;
273 AllocHeapParams.Persist = HEAP_SYSTEM_MEM;
274 if (HeapAllocateBuffer (&AllocHeapParams, State->ConfigHandle) == AGESA_SUCCESS) {
275 State->NodeToSocketDieMap = (NODE_TO_SOCKET_DIE_MAP)AllocHeapParams.BufferPtr;
276 // Initialize shared data structures
277 for (i = 0; i < MAX_NODES; i++) {
278 (*State->NodeToSocketDieMap)[i].Socket = HT_LIST_TERMINAL;
279 (*State->NodeToSocketDieMap)[i].Die = HT_LIST_TERMINAL;
284 /*----------------------------------------------------------------------------------------*/
286 * Get the minimum Northbridge frequency for the system.
288 * @HtInterfaceMethod{::F_GET_MIN_NB_CORE_FREQ}
290 * Invoke the CPU component power mgt interface.
292 * @param[in] PlatformConfig Platform profile/build option config structure.
293 * @param[in] StdHeader Config for library and services.
295 * @return Frequency in MHz.
300 IN PLATFORM_CONFIGURATION *PlatformConfig,
301 IN AMD_CONFIG_PARAMS *StdHeader
307 OptionMultiSocketConfiguration.GetMinNbCof (PlatformConfig, &MinSysNbFreq, &MinP0NbFreq, StdHeader);
309 ASSERT (MinSysNbFreq != 0);
315 * @page physicalsockethowto Physical Socket Map, How To Create
317 * To create a physical system socket map for a platform:
319 * - Start at the Node which will be the BSP.
321 * - Begin a breadth first enumeration of all the coherent Links between sockets
322 * by creating a socket structure for each socket connection from the BSP.
323 * For example, if the BSP is in socket zero and Link one connects to socket two,
324 * create socket {0, 1, 2}.
326 * - When all Links from the BSP are described, go to the first socket connected
327 * to the BSP and continue the breadth first enumeration.
329 * - It should not be necessary to describe the back Links; in the example above, there
330 * should be no need to create {2, 1, 0} (assuming socket two connects back to
331 * socket zero on its Link one).
335 * - Every socket except the BSP's (usually zero) must be listed as a targetSocket,
336 * at least once. Some sockets may be listed more than once.
338 * - There usually should be at least as many entries as Links. An exception is a
339 * fully connected system, only the Links from the BSP are needed.
341 * - Every socket but the last one in the breadth first order should usually have one
342 * or more entries listing it as a currentSocket. (The last one has only back Links.)
344 * There are no strict assumptions about the ordering of the socket structures.
347 /*----------------------------------------------------------------------------------------*/
349 * Update maps between Sockets and Nodes for a specific newly discovered node.
351 * @HtInterfaceMethod{::F_SET_NODE_TO_SOCKET_MAP}
353 * There are two methods for providing socket naming of nodes.
355 * Hardware Method (preferred): A value strapped in hardware by the board is read and
356 * passed to this routine.
358 * Software Method: The current node's socket is looked up, since it was
359 * previously a new node and went through this process. The link is converted to
360 * a package level link. A user data structure describing the package level
361 * layout of the system is searched for the current node's socket and package link,
362 * and now we know the new node's socket.
364 * In either case, the Socket, Module to Node map and the Node to Socket, Module
365 * map are updated with the new node, socket, and module.
367 * Data needed to do this is passed in to the routine as arguments rather than read by this routine,
368 * so that it is not necessary to know a valid temporary route to either node at the time this code runs.
370 * @param[in] Node Node from which a new node was discovered
371 * @param[in] CurrentNodeModule The current node's module id in it's processor.
372 * @param[in] PackageLink The package link for the current node's link.
373 * @param[in] NewNode The new node's id
374 * @param[in] HardwareSocket If we use the hardware method (preferred), this is the socket of new node.
375 * @param[in] Module The new node's module id in it's processor.
376 * @param[in] State our State
381 IN UINT8 CurrentNodeModule,
382 IN UINT8 PackageLink,
384 IN UINT8 HardwareSocket,
391 SYSTEM_PHYSICAL_SOCKET_MAP *Map;
393 // While this code could be written to recover from a NULL socket map, AGESA cannot function without one.
394 ASSERT (State->SocketDieToNodeMap != NULL);
396 if (State->HtBlock->SystemPhysicalSocketMap != NULL) {
398 // Find the logical Node from which a new Node was discovered in the Node field of
399 // some socket. It must already be there, Nodes are assigned ascending.
401 for (SourceSocket = 0; SourceSocket < MAX_SOCKETS; SourceSocket++) {
402 if ((*State->SocketDieToNodeMap)[SourceSocket][CurrentNodeModule].Node == Node) {
406 // This ASSERT should be understood as "the Node did not have a match", not as a limit check on SourceSocket.
407 ASSERT (SourceSocket != MAX_SOCKETS);
409 // Find the sourceSocket in the CurrentSocket field, for the Link on which a new Node
410 // was discovered. When we find an entry with that socket and Link number, update the
411 // Node for that socket.
413 if (IsPackageLinkInternal (PackageLink)) {
414 // Internal Nodes are in the same socket, don't search the physical system map.
415 TargetSocket = SourceSocket;
417 // Find the target socket in the physical system map.
418 Map = State->HtBlock->SystemPhysicalSocketMap;
419 while ((Map->CurrentSocket != 0xFF) &&
420 ((Map->CurrentSocket != SourceSocket) || (Map->CurrentLink != PackageLink))) {
423 ASSERT (Map->CurrentSocket != 0xFF);
424 TargetSocket = Map->TargetSocket;
427 // The BSP (BSN, if you will) has no predecessor node from which it is discovered.
431 // Use the hardware method
432 // The hardware strapped socket id is passed to us in this case.
433 TargetSocket = HardwareSocket;
435 // If the target socket, module is already mapped to something, that's not good. Socket labeling conflict.
436 // Check that the board is strapped correctly. If not you need a SystemPhysicalSocketMap. If you have one,
437 // check it for correctness.
438 ASSERT ((*State->SocketDieToNodeMap)[TargetSocket][Module].Node == 0xFF);
439 // Update the map for the rest of agesa
440 (*State->SocketDieToNodeMap)[TargetSocket][Module].Node = NewNode;
441 // and the node to socket map
442 ASSERT (State->NodeToSocketDieMap != NULL);
443 (*State->NodeToSocketDieMap)[NewNode].Socket = TargetSocket;
444 (*State->NodeToSocketDieMap)[NewNode].Die = Module;
447 /*----------------------------------------------------------------------------------------*/
449 * Clean up the map structures after severe event has caused a fall back to 1 node.
451 * @HtInterfaceMethod{::F_CLEAN_MAPS_AFTER_ERROR}
453 * @param[in] State Our state, access to socket, node maps
457 CleanMapsAfterError (
465 ASSERT (State->NodeToSocketDieMap != NULL);
466 ASSERT (State->SocketDieToNodeMap != NULL);
468 // Clear all the socket, module items except for the socket and module containing node zero.
469 for (Socket = 0; Socket < MAX_SOCKETS; Socket++) {
470 for (Module = 0; Module < MAX_DIES; Module++) {
471 if (((*State->NodeToSocketDieMap)[0].Socket != Socket) || ((*State->NodeToSocketDieMap)[0].Die != Module)) {
472 (*State->SocketDieToNodeMap)[Socket][Module].Node = HT_LIST_TERMINAL;
473 (*State->SocketDieToNodeMap)[Socket][Module].LowCore = HT_LIST_TERMINAL;
474 (*State->SocketDieToNodeMap)[Socket][Module].HighCore = HT_LIST_TERMINAL;
478 // Clear all the node items except for node zero.
479 for (Node = 1; Node < MAX_NODES; Node++) {
480 (*State->NodeToSocketDieMap)[Node].Socket = HT_LIST_TERMINAL;
481 (*State->NodeToSocketDieMap)[Node].Die = HT_LIST_TERMINAL;
485 /*----------------------------------------------------------------------------------------*/
487 * Post Node id and other context info to AP cores via mailbox.
489 * @HtInterfaceMethod{::F_POST_MAP_TO_AP}
491 * Since Ap's can not view map until after mp communication is established,
492 * provide them with initial context info via a mailbox register. A mailbox
493 * register is one that can be written in PCI space and read in MSR space.
495 * @param[in] State Our state, access to socket, node maps
504 AP_MAILBOXES ApMailboxes;
507 AGESA_STATUS CalledStatus;
509 // Dispatch any features (such as Preserve Mailbox) that need to run as soon as discovery is completed.
510 IDS_HDT_CONSOLE (CPU_TRACE, " Dispatch CPU features after HT discovery\n");
511 CalledStatus = DispatchCpuFeatures (CPU_FEAT_AFTER_COHERENT_DISCOVERY, State->PlatformConfiguration, State->ConfigHandle);
513 ASSERT (State->Fabric != NULL);
515 // Compute the degree of the system by finding the maximum degree of any node.
516 for (Node = 0; Node < (State->NodesDiscovered + 1); Node++) {
517 if (State->Fabric->SysDegree[Node] > Degree) {
518 Degree = State->Fabric->SysDegree[Node];
521 // Post the information on all nodes.
522 for (Node = 0; Node < (State->NodesDiscovered + 1); Node++) {
525 State->Nb->GetModuleInfo (Node, &ModuleType, &Module, State->Nb);
526 ApMailboxes.ApMailInfo.Info = 0;
527 ApMailboxes.ApMailInfo.Fields.Node = Node;
528 ApMailboxes.ApMailInfo.Fields.Socket = State->HtInterface->GetSocketFromMap (Node, State);
529 ApMailboxes.ApMailInfo.Fields.ModuleType = ModuleType;
530 ApMailboxes.ApMailInfo.Fields.Module = Module;
531 ApMailboxes.ApMailExtInfo.Info = 0;
532 ApMailboxes.ApMailExtInfo.Fields.SystemDegree = Degree;
533 // other fields of the extended info are used during ap init, and will be initialized at that time.
534 State->Nb->PostMailbox (Node, ApMailboxes, State->Nb);
536 // Now that the mailboxes have been initialized, cache the info on the BSC. The APs
537 // will cache during heap initialization.
538 CacheApMailbox (State->ConfigHandle);