blob: 50281e144e8649f5af91c9f1bc3e75f415797f15 [file] [log] [blame]
Frank Vibrans2b4c8312011-02-14 18:30:54 +00001/* $NoKeywords:$ */
2/**
3 * @file
4 *
5 * HyperTransport features and sequence implementation.
6 *
7 * Implements the external AmdHtInitialize entry point.
8 * Contains routines for directing the sequence of available features.
9 * Mostly, but not exclusively, AGESA_TESTPOINT invocations should be
10 * contained in this file, and not in the feature code.
11 *
12 * From a build option perspective, it may be that a few lines could be removed
13 * from compilation in this file for certain options. It is considered that
14 * the code savings from this are too small to be of concern and this file
15 * should not have any explicit build option implementation.
16 *
17 * @xrefitem bom "File Content Label" "Release Content"
18 * @e project: AGESA
19 * @e sub-project: HyperTransport
20 * @e \$Revision: 35978 $ @e \$Date: 2010-08-07 02:18:50 +0800 (Sat, 07 Aug 2010) $
21 *
22 */
23/*
24 *****************************************************************************
25 *
26 * Copyright (c) 2011, Advanced Micro Devices, Inc.
27 * All rights reserved.
Edward O'Callaghan1542a6f2014-07-06 19:24:06 +100028 *
Frank Vibrans2b4c8312011-02-14 18:30:54 +000029 * Redistribution and use in source and binary forms, with or without
30 * modification, are permitted provided that the following conditions are met:
31 * * Redistributions of source code must retain the above copyright
32 * notice, this list of conditions and the following disclaimer.
33 * * Redistributions in binary form must reproduce the above copyright
34 * notice, this list of conditions and the following disclaimer in the
35 * documentation and/or other materials provided with the distribution.
Edward O'Callaghan1542a6f2014-07-06 19:24:06 +100036 * * Neither the name of Advanced Micro Devices, Inc. nor the names of
37 * its contributors may be used to endorse or promote products derived
Frank Vibrans2b4c8312011-02-14 18:30:54 +000038 * from this software without specific prior written permission.
Edward O'Callaghan1542a6f2014-07-06 19:24:06 +100039 *
Frank Vibrans2b4c8312011-02-14 18:30:54 +000040 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
41 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
42 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
43 * DISCLAIMED. IN NO EVENT SHALL ADVANCED MICRO DEVICES, INC. BE LIABLE FOR ANY
44 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
45 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
46 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
47 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
48 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
49 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Edward O'Callaghan1542a6f2014-07-06 19:24:06 +100050 *
Frank Vibrans2b4c8312011-02-14 18:30:54 +000051 * ***************************************************************************
52 *
53 */
54
55/*
56 *----------------------------------------------------------------------------
57 * MODULES USED
58 *
59 *----------------------------------------------------------------------------
60 */
61
62
63
64#include "AGESA.h"
65#include "AdvancedApi.h"
66#include "amdlib.h"
67#include "Ids.h"
68#include "Topology.h"
69#include "htFeat.h"
70#include "htInterface.h"
71#include "htNb.h"
72#include "heapManager.h"
73#include "cpuServices.h"
74#include "OptionsHt.h"
75#include "Filecode.h"
76CODE_GROUP (G1_PEICC)
77RDATA_GROUP (G1_PEICC)
78
79#define FILECODE PROC_HT_HTMAIN_FILECODE
80#define APIC_Base_BSP 8
81#define APIC_Base 0x1b
82
83extern OPTION_HT_CONFIGURATION OptionHtConfiguration;
84
85BOOLEAN
86STATIC
87IsBootCore (
88 IN STATE_DATA *State
89 );
90
91/*----------------------------------------------------------------------------------------*/
92/**
93 * Update maps with the core range for each module.
94 *
95 * Cores are numbered relative to a Processor, but sometimes there is a need to know the
96 * starting and ending core ids on a particular node. This same info is also useful for
97 * supporting the Core count on a node other than the one currently executing.
98 *
99 * For each Processor, get the core count of each node using the family specific PCI core count
100 * interface. The order of cores in a processor, and whether it is special for the BSP is family
101 * specific. But whether the processor orders core ids by module or node, iterate in the right
102 * order and use the counts to determine each start and end range.
103 *
104 * Update compute unit status for each node.
105 *
106 * @param[in] State number of Nodes discovered.
107*/
108VOID
109STATIC
110UpdateCoreRanges (
111 IN STATE_DATA *State
112 )
113{
114 UINT8 Node;
115 UINT8 ProcessorCores;
116 UINT8 ModuleCoreCount[MAX_DIES];
117 UINT8 Socket;
118 UINT8 Module;
119
120 ASSERT (State->SocketDieToNodeMap != NULL);
121 ASSERT (State->NodeToSocketDieMap != NULL);
122
123 for (Socket = 0; Socket < MAX_SOCKETS; Socket++) {
124 // Is a Processor present in Socket?
125 if ((*State->SocketDieToNodeMap)[Socket][0].Node != HT_LIST_TERMINAL) {
126 // Get all the Module core counts for this processor
127 // Note that the core counts are 1 based counts.
128 // Since Compute Unit info is not module ordering dependent, write it now.
129 for (Module = 0; Module < MAX_DIES; Module++) {
130 if ((*State->SocketDieToNodeMap)[Socket][Module].Node != HT_LIST_TERMINAL) {
131 ModuleCoreCount[Module] = State->Nb->GetNumCoresOnNode ((*State->SocketDieToNodeMap)[Socket][Module].Node, State->Nb);
132 (*State->SocketDieToNodeMap)[Socket][Module].EnabledComputeUnits =
133 State->Nb->GetEnabledComputeUnits ((*State->SocketDieToNodeMap)[Socket][Module].Node, State->Nb);
134 (*State->SocketDieToNodeMap)[Socket][Module].DualCoreComputeUnits =
135 State->Nb->GetDualCoreComputeUnits ((*State->SocketDieToNodeMap)[Socket][Module].Node, State->Nb);
136 } else {
137 ModuleCoreCount[Module] = 0;
138 }
139 }
140 // Determine the core ordering rule for this processor.
141 if ((((*State->NodeToSocketDieMap)[0].Socket == Socket) && State->Nb->IsOrderBSPCoresByNode) ||
142 (!State->Nb->IsOrderCoresByModule)) {
143 // Order core ranges on this processor by Node Id.
144 ProcessorCores = 0;
145 for (Node = 0; Node < State->Nb->GetNodeCount (State->Nb); Node++) {
146 // Is this node a module in this processor?
147 if ((*State->NodeToSocketDieMap)[Node].Socket == Socket) {
148 Module = (*State->NodeToSocketDieMap)[Node].Die;
149 if (ModuleCoreCount[Module] != 0) {
150 (*State->SocketDieToNodeMap)[Socket][Module].LowCore = ProcessorCores;
151 (*State->SocketDieToNodeMap)[Socket][Module].HighCore = ProcessorCores + (ModuleCoreCount[Module] - 1);
152 IDS_HDT_CONSOLE (
153 HT_TRACE,
154 (IsBootCore (State) ?
155 "Topology: Socket %d, Die %d, is Node %d, with Cores %d thru %d. Compute Unit status (0x%x,0x%x).\n" :
156 ""),
157 Socket,
158 Module,
159 Node,
160 (*State->SocketDieToNodeMap)[Socket][Module].LowCore,
161 (*State->SocketDieToNodeMap)[Socket][Module].HighCore,
162 (*State->SocketDieToNodeMap)[Socket][Module].EnabledComputeUnits,
163 (*State->SocketDieToNodeMap)[Socket][Module].DualCoreComputeUnits
164 );
165 ProcessorCores = ProcessorCores + ModuleCoreCount[Module];
166 }
167 }
168 }
169 } else {
170 // Order core ranges in this processor by Module Id.
171 ProcessorCores = 0;
172 for (Module = 0; Module < MAX_DIES; Module++) {
173 if (ModuleCoreCount[Module] != 0) {
174 (*State->SocketDieToNodeMap)[Socket][Module].LowCore = ProcessorCores;
175 (*State->SocketDieToNodeMap)[Socket][Module].HighCore = ProcessorCores + (ModuleCoreCount[Module] - 1);
176 IDS_HDT_CONSOLE (
177 HT_TRACE,
178 (IsBootCore (State) ?
179 "Topology: Socket %d, Die %d, is Node %d, with Cores %d thru %d. Compute Unit status (0x%x,0x%x).\n" :
180 ""),
181 Socket,
182 Module,
183 (*State->SocketDieToNodeMap)[Socket][Module].Node,
184 (*State->SocketDieToNodeMap)[Socket][Module].LowCore,
185 (*State->SocketDieToNodeMap)[Socket][Module].HighCore,
186 (*State->SocketDieToNodeMap)[Socket][Module].EnabledComputeUnits,
187 (*State->SocketDieToNodeMap)[Socket][Module].DualCoreComputeUnits
188 );
189 ProcessorCores = ProcessorCores + ModuleCoreCount[Module];
190 }
191 }
192 }
193 }
194 }
195}
196
197/*----------------------------------------------------------------------------------------*/
198/**
199 * Complete the coherent init with any system level initialization.
200 *
201 * Find the total number of cores and update the number of Nodes and cores in all cpus.
202 * Limit cpu config access to installed cpus.
203 *
204 * @param[in] State number of Nodes discovered.
205*/
206VOID
207STATIC
208FinalizeCoherentInit (
209 IN STATE_DATA *State
210 )
211{
212 UINT8 Node;
213 UINT8 TotalCores;
214
215 TotalCores = 0;
216
217 for (Node = 0; Node < (State->NodesDiscovered + 1); Node++) {
218 TotalCores = TotalCores + State->Nb->GetNumCoresOnNode (Node, State->Nb);
219 }
220
221 for (Node = 0; Node < (State->NodesDiscovered + 1); Node++) {
222 State->Nb->SetTotalNodesAndCores (Node, State->NodesDiscovered + 1, TotalCores, State->Nb);
223 }
224
225 // Set all nodes to limit config space based on node count, after all nodes have a valid count.
226 // (just being cautious, probably we could combine the loops.)
227 for (Node = 0; Node < (State->NodesDiscovered + 1); Node++) {
228 State->Nb->LimitNodes (Node, State->Nb);
229 }
230}
231
232/*----------------------------------------------------------------------------------------*/
233/**
234 * Initialize the coherent fabric.
235 *
236 * Perform discovery and initialization of the coherent fabric, for builds including
237 * support for multiple coherent nodes.
238 *
239 * @param[in] State global state
240 */
241VOID
242STATIC
243CoherentInit (
244 IN OUT STATE_DATA *State
245 )
246{
247 UINT8 i;
248 UINT8 j;
249 UINT8 ModuleType;
250 UINT8 Module;
251 UINT8 HardwareSocket;
252 COHERENT_FABRIC Fabric;
253
254 // Because Node 0, the BSP, is not discovered, initialize info about it specially here.
255 // Allocate Socket Die Map.
256 // While the BSP is always capable of being the only processor in the system, call the
257 // IsExceededCapable method to make sure the BSP's capability is included in the aggregate system
258 // capability. We don't care to check the return value.
259 //
260 State->Fabric = &Fabric;
261 State->NodesDiscovered = 0;
262 State->TotalLinks = 0;
263 State->SysMpCap = MAX_NODES;
264 State->Nb->IsExceededCapable (0, State, State->Nb);
265 HardwareSocket = State->Nb->GetSocket (0, 0, State->Nb);
266 ModuleType = 0;
267 Module = 0;
268 State->Nb->GetModuleInfo (0, &ModuleType, &Module, State->Nb);
269 // No predecessor info for BSP, so pass 0xFF for those parameters.
270 State->HtInterface->SetNodeToSocketMap (0xFF, 0xFF, 0xFF, 0, HardwareSocket, Module, State);
271
272 // Initialize system state data structures
273 for (i = 0; i < MAX_NODES; i++) {
274 State->Fabric->SysDegree[i] = 0;
275 for (j = 0; j < MAX_NODES; j++) {
276 State->Fabric->SysMatrix[i][j] = 0;
277 }
278 }
279
280 //
281 // Call the coherent init features
282 //
283
284 // Discovery
285 State->HtFeatures->CoherentDiscovery (State);
286 State->HtInterface->PostMapToAp (State);
287 // Topology matching and Routing
288 AGESA_TESTPOINT (TpProcHtTopology, State->ConfigHandle);
289 State->HtFeatures->LookupComputeAndLoadRoutingTables (State);
290 State->HtFeatures->MakeHopCountTable (State);
291
292 // UpdateCoreRanges requires the other maps to be initialized, and the node count set.
293 FinalizeCoherentInit (State);
294 UpdateCoreRanges (State);
295 State->Fabric = NULL;
296}
297
298/***************************************************************************
299 *** Non-coherent init code ***
300 *** Algorithms ***
301 ***************************************************************************/
302/*----------------------------------------------------------------------------------------*/
303/**
304 * Initialize the non-coherent fabric.
305 *
306 * Begin with the Compat Link on the BSP, then find and initialize all other
307 * non-coherent chains.
308 *
309 * @param[in] State our global state
310 */
311VOID
312STATIC
313NcInit (
314 IN STATE_DATA *State
315 )
316{
317 UINT8 Node;
318 UINT8 Link;
319 UINT8 CompatLink;
320 FINAL_LINK_STATE FinalLinkState;
321
322 // Initialize the southbridge chain.
323 State->AutoBusCurrent = State->HtBlock->AutoBusStart;
324 State->UsedCfgMapEntries = 0;
325 CompatLink = State->Nb->ReadSouthbridgeLink (State->Nb);
326 State->HtFeatures->ProcessLink (0, CompatLink, TRUE, State);
327
328 // Find and initialize all other non-coherent chains.
329 for (Node = 0; Node <= State->NodesDiscovered; Node++) {
330 for (Link = 0; Link < State->Nb->MaxLinks; Link++) {
331 // Skip the Link, if any of these tests indicate
332 FinalLinkState = State->HtInterface->GetIgnoreLink (Node, Link, State->Nb->DefaultIgnoreLinkList, State);
333 if (FinalLinkState == UNMATCHED) {
334 if ( !((Node == 0) && (Link == CompatLink))) {
335 if ( !(State->Nb->ReadTrueLinkFailStatus (Node, Link, State, State->Nb))) {
336 if (State->Nb->VerifyLinkIsNonCoherent (Node, Link, State->Nb)) {
337 State->HtFeatures->ProcessLink (Node, Link, FALSE, State);
338 }
339 }
340 }
341 }
342 }
343 }
344}
345
346/***************************************************************************
347 *** Link Optimization ***
348 ***************************************************************************/
349
350/*----------------------------------------------------------------------------------------*/
351/**
352 * Optimize Link Features.
353 *
354 * Based on Link capabilities, apply optimization rules to come up with the best
355 * settings, including several external limit decision from the interface. This includes
356 * handling of subLinks. Finally, after the port list data is updated, set the hardware
357 * state for all Links.
358 *
359 * @param[in] State our global state
360 */
361VOID
362STATIC
363LinkOptimization (
364 IN STATE_DATA *State
365 )
366{
367 AGESA_TESTPOINT (TpProcHtOptGather, State->ConfigHandle);
368 State->HtFeatures->GatherLinkData (State);
369
370 AGESA_TESTPOINT (TpProcHtOptRegang, State->ConfigHandle);
371 State->HtFeatures->RegangLinks (State);
372
373 AGESA_TESTPOINT (TpProcHtOptLinks, State->ConfigHandle);
374 State->HtFeatures->SelectOptimalWidthAndFrequency (State);
375
376 // A likely cause of mixed Retry settings on coherent links is sublink ratio balancing
377 // so check this after doing the sublinks.
378 AGESA_TESTPOINT (TpProcHtOptSubLinks, State->ConfigHandle);
379 State->HtFeatures->SubLinkRatioFixup (State);
380 if (State->HtFeatures->IsCoherentRetryFixup (State)) {
381 // Fix sublinks again within HT1 only frequencies, as ratios may be invalid again.
382 State->HtFeatures->SubLinkRatioFixup (State);
383 }
384
385 AGESA_TESTPOINT (TpProcHtOptFinish, State->ConfigHandle);
386 State->HtFeatures->SetLinkData (State);
387}
388
389/*----------------------------------------------------------------------------------------*/
390/**
391 * Handle system and performance tunings.
392 *
393 * Including traffic distribution, fifo and
394 * buffer tuning that can't be placed in the register table,
395 * and special config tunings.
396 *
397 * @param[in] State Total Nodes, port list data
398 */
399VOID
400STATIC
401Tuning (
402 IN STATE_DATA *State
403 )
404{
405 UINT8 Node;
406
407 // See if traffic distribution can be done and do it if so.
408 //
409 AGESA_TESTPOINT (TpProcHtTrafficDist, State->ConfigHandle);
410 State->HtFeatures->TrafficDistribution (State);
411
412 // For each Node, invoke northbridge specific buffer tunings that can not be done in reg table.
413 //
414 AGESA_TESTPOINT (TpProcHtTuning, State->ConfigHandle);
415 for (Node = 0; Node < (State->NodesDiscovered + 1); Node++) {
416 State->Nb->BufferOptimizations (Node, State, State->Nb);
417 }
418}
419
420/*----------------------------------------------------------------------------------------*/
421/**
422 * Initialize the Node and Socket maps for an AP Core.
423 *
424 * In each core's local heap, create a Node to Socket map and a Socket/Module to Node map.
425 * The mapping is filled in by reading the AP Mailboxes from PCI config on each node.
426 *
427 * @param[in] State global state, input data
428 *
429 */
430VOID
431STATIC
432InitApMaps (
433 IN STATE_DATA *State
434 )
435{
436 UINT8 Node;
437 AP_MAIL_INFO NodeApMailBox;
438
439 // There is no option to not have socket - node maps, if they aren't allocated that is a fatal bug.
440 ASSERT (State->SocketDieToNodeMap != NULL);
441 ASSERT (State->NodeToSocketDieMap != NULL);
442
443 for (Node = 0; Node < State->Nb->GetNodeCount (State->Nb); Node++) {
444 NodeApMailBox = State->Nb->RetrieveMailbox (Node, State->Nb);
445 (*State->SocketDieToNodeMap)[NodeApMailBox.Fields.Socket][NodeApMailBox.Fields.Module].Node = Node;
446 (*State->NodeToSocketDieMap)[Node].Socket = (UINT8)NodeApMailBox.Fields.Socket;
447 (*State->NodeToSocketDieMap)[Node].Die = (UINT8)NodeApMailBox.Fields.Module;
448 }
449 // This requires the other maps to be initialized.
450 UpdateCoreRanges (State);
451}
452
453/*----------------------------------------------------------------------------------------*/
454/**
455 * Is the currently running core the BSC?
456 *
457 * Determine whether the init steps for BSC or AP core should be run.
458 *
459 * @param[in] State global state, input data
460 *
461 * @retval TRUE This is the boot core.
462 * @retval FALSE This is not the boot core.
463 */
464BOOLEAN
465STATIC
466IsBootCore (
467 IN STATE_DATA *State
468 )
469{
470 UINT64 Value;
471
472 LibAmdMsrRead (APIC_Base, &Value, State->ConfigHandle);
473
474 return ((BOOLEAN) (((UINT32) (Value & 0xFFFFFFFF) & ((UINT32)1 << APIC_Base_BSP)) != 0));
475}
476
477/***************************************************************************
478 *** HT Initialize ***
479 ***************************************************************************/
480
481/*----------------------------------------------------------------------------------------*/
482/**
483 * The top level external interface for Hypertransport Initialization.
484 *
485 * Create our initial internal state, initialize the coherent fabric,
486 * initialize the non-coherent chains, and perform any required fabric tuning or
487 * optimization.
488 *
489 * @param[in] StdHeader Opaque handle to standard config header
490 * @param[in] PlatformConfiguration The platform configuration options.
491 * @param[in] AmdHtInterface HT Interface structure.
492 *
493 * @retval AGESA_SUCCESS Only information events logged.
494 * @retval AGESA_ALERT Sync Flood or CRC error logged.
495 * @retval AGESA_WARNING Example: expected capability not found
496 * @retval AGESA_ERROR logged events indicating some devices may not be available
497 * @retval AGESA_FATAL Mixed Family or MP capability mismatch
498 *
499 */
500AGESA_STATUS
501AmdHtInitialize (
502 IN AMD_CONFIG_PARAMS *StdHeader,
503 IN PLATFORM_CONFIGURATION *PlatformConfiguration,
504 IN AMD_HT_INTERFACE *AmdHtInterface
505 )
506{
507 STATE_DATA State;
508 NORTHBRIDGE Nb;
509 HT_FEATURES HtFeatures;
510 HT_INTERFACE HtInterface;
511 AGESA_STATUS DeallocateStatus;
512 AP_MAIL_INFO ApMailboxInfo;
513 UINT8 ApNode;
514
515 ALLOCATE_HEAP_PARAMS AllocHeapParams;
516
517 State.HtBlock = AmdHtInterface;
518 State.ConfigHandle = StdHeader;
519 State.PlatformConfiguration = PlatformConfiguration;
520
521 // Get the current HT internal interface (to HtBlock data)
522 NewHtInterface (&HtInterface, State.ConfigHandle);
523 State.HtInterface = &HtInterface;
524
525 // Get the current HT Feature Set
526 NewHtFeatures (&HtFeatures, State.ConfigHandle);
527 State.HtFeatures = &HtFeatures;
528
529 // Initialize from static options
530 State.IsUsingRecoveryHt = OptionHtConfiguration.IsUsingRecoveryHt;
531 State.IsSetHtCrcFlood = OptionHtConfiguration.IsSetHtCrcFlood;
532 State.IsUsingUnitIdClumping = OptionHtConfiguration.IsUsingUnitIdClumping;
533
534 // Initialize for status and event output
535 State.MaxEventClass = AGESA_SUCCESS;
536
537 // Allocate permanent heap structs that are interfaces to other AGESA services.
538 State.HtInterface->NewNodeAndSocketTables (&State);
539
540 if (IsBootCore (&State)) {
541 AGESA_TESTPOINT (TpProcHtEntry, State.ConfigHandle);
542 // Allocate Bsp only interface heap structs.
543 State.HtInterface->NewHopCountTable (&State);
544 // Allocate heap for our temporary working space.
545 AllocHeapParams.RequestedBufferSize = (sizeof (PORT_DESCRIPTOR) * (MAX_PLATFORM_LINKS * 2));
546 AllocHeapParams.BufferHandle = HT_STATE_DATA_HANDLE;
547 AllocHeapParams.Persist = HEAP_LOCAL_CACHE;
548 if (HeapAllocateBuffer (&AllocHeapParams, State.ConfigHandle) == AGESA_SUCCESS) {
549 State.PortList = (PORT_LIST)AllocHeapParams.BufferPtr;
550 // Create the BSP's northbridge.
551 NewNorthBridge (0, &State, &Nb);
552 State.Nb = &Nb;
553
554 CoherentInit (&State);
555 NcInit (&State);
556 LinkOptimization (&State);
557 Tuning (&State);
558
559 DeallocateStatus = HeapDeallocateBuffer (HT_STATE_DATA_HANDLE, State.ConfigHandle);
560 ASSERT (DeallocateStatus == AGESA_SUCCESS);
561 AGESA_TESTPOINT (TpProcHtDone, State.ConfigHandle);
562 } else {
563 ASSERT (FALSE);
564 State.MaxEventClass = AGESA_ERROR;
565 // Cannot Log entry due to heap allocate failed.
566 }
567 } else {
568 // Do the AP HT Init, which produces Node and Socket Maps for the AP's use.
569 AGESA_TESTPOINT (TpProcHtApMapEntry, State.ConfigHandle);
570 GetApMailbox (&ApMailboxInfo.Info, State.ConfigHandle);
571 ASSERT (ApMailboxInfo.Fields.Node < MAX_NODES);
572 ApNode = (UINT8)ApMailboxInfo.Fields.Node;
573 NewNorthBridge (ApNode, &State, &Nb);
574 State.Nb = &Nb;
575 InitApMaps (&State);
576 AGESA_TESTPOINT (TpProcHtApMapDone, State.ConfigHandle);
577 }
578 return State.MaxEventClass;
579}