blob: be55c063bb87f66bf212020b3c55d642a3df0470 [file] [log] [blame]
Marc Jones8ae8c882007-12-19 01:32:08 +00001/*
Stefan Reinauer7e61e452008-01-18 10:35:56 +00002 * This file is part of the coreboot project.
Marc Jones8ae8c882007-12-19 01:32:08 +00003 *
4 * Copyright (C) 2007 Advanced Micro Devices, Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20/*
21 *----------------------------------------------------------------------------
22 * MODULES USED
23 *
24 *----------------------------------------------------------------------------
25 */
26
27#undef FILECODE
28#define FILECODE 0xF001
29
30#include "comlib.h"
31#include "h3finit.h"
32#include "h3ffeat.h"
33#include "h3ncmn.h"
34#include "h3gtopo.h"
35#include "AsPsNb.h"
36/* this is pre-ram so include the required C files here */
37#include "comlib.c"
38#include "AsPsNb.c"
39#include "h3ncmn.c"
40
41/*----------------------------------------------------------------------------
42 * DEFINITIONS AND MACROS
43 *
44 *----------------------------------------------------------------------------
45 */
46
47#undef FILECODE
48#define FILECODE 0xF001
49
50/* APIC defines from amdgesa.inc, which can't be included in to c code. */
51#define APIC_Base_BSP 8
52#define APIC_Base 0x1b
53
54/*----------------------------------------------------------------------------
55 * TYPEDEFS AND STRUCTURES
56 *
57 *----------------------------------------------------------------------------
58 */
59
60/*----------------------------------------------------------------------------
61 * PROTOTYPES OF LOCAL FUNCTIONS
62 *
63 *----------------------------------------------------------------------------
64 */
65
66/*----------------------------------------------------------------------------
67 * EXPORTED FUNCTIONS
68 *
69 *----------------------------------------------------------------------------
70 */
71
72/*----------------------------------------------------------------------------
73 * LOCAL FUNCTIONS
74 *
75 *----------------------------------------------------------------------------
76 */
77#ifndef HT_BUILD_NC_ONLY
78/*
79 **************************************************************************
80 * Routing table decompressor
81 **************************************************************************
82 */
83
84/*
85 **************************************************************************
86 * Graph Support routines
87 * These routines provide support for dealing with the graph representation
88 * of the topologies, along with the routing table information for that topology.
89 * The routing information is compressed and these routines currently decompress
90 * 'on the fly'. A graph is represented as a set of routes. All the edges in the
91 * graph are routes; a direct route from node i to node j exists in the graph IFF
92 * there is an edge directly connecting node i to node j. All other routes designate
93 * the edge which the route to that node initially takes, by designating a node
94 * to which a direct connection exists. That is, the route to non-adjacent node j
95 * from node i specifies node k where node i directly connects to node k.
96 *
97 *
98 * pseudo definition of compressed graph:
99 * typedef struct
100 * {
101 * BIT broadcast[8];
102 * uint4 responseRoute;
103 * uint4 requestRoute;
104 * } sRoute;
105 * typedef struct
106 * {
107 * u8 size;
108 * sRoute graph[size][size];
109 * } sGraph;
110 *
111 **************************************************************************
112 */
113
114/*----------------------------------------------------------------------------------------
Marc Jones212486e2008-07-17 19:50:37 +0000115 * u8
Marc Jones8ae8c882007-12-19 01:32:08 +0000116 * graphHowManyNodes(u8 *graph)
117 *
118 * Description:
119 * Returns the number of nodes in the compressed graph
120 *
121 * Parameters:
122 * @param[in] u8 graph = a compressed graph
123 * @param[out] u8 results = the number of nodes in the graph
124 * ---------------------------------------------------------------------------------------
125 */
Marc Jones212486e2008-07-17 19:50:37 +0000126u8 graphHowManyNodes(u8 *graph)
Marc Jones8ae8c882007-12-19 01:32:08 +0000127{
128 return graph[0];
129}
130
131/*----------------------------------------------------------------------------------------
132 * BOOL
133 * graphIsAdjacent(u8 *graph, u8 nodeA, u8 nodeB)
134 *
135 * Description:
136 * Returns true if NodeA is directly connected to NodeB, false otherwise
137 * (if NodeA == NodeB also returns false)
138 * Relies on rule that directly connected nodes always route requests directly.
139 *
140 * Parameters:
141 * @param[in] u8 graph = the graph to examine
142 * @param[in] u8 nodeA = the node number of the first node
143 * @param[in] u8 nodeB = the node number of the second node
144 * @param[out] BOOL results = true if nodeA connects to nodeB false if not
145 * ---------------------------------------------------------------------------------------
146 */
147BOOL graphIsAdjacent(u8 *graph, u8 nodeA, u8 nodeB)
148{
149 u8 size = graph[0];
150 ASSERT(size <= MAX_NODES);
151 ASSERT((nodeA < size) && (nodeB < size));
152 return (graph[1+(nodeA*size+nodeB)*2+1] & 0x0F) == nodeB;
153}
154
155/*----------------------------------------------------------------------------------------
156 * u8
157 * graphGetRsp(u8 *graph, u8 nodeA, u8 nodeB)
158 *
159 * Description:
160 * Returns the graph node used by nodeA to route responses targeted at nodeB.
161 * This will be a node directly connected to nodeA (possibly nodeB itself),
162 * or "Route to Self" if nodeA and nodeB are the same node.
163 * Note that all node numbers are abstract node numbers of the topology graph,
164 * it is the responsibility of the caller to apply any permutation needed.
165 *
166 * Parameters:
167 * @param[in] u8 graph = the graph to examine
168 * @param[in] u8 nodeA = the node number of the first node
169 * @param[in] u8 nodeB = the node number of the second node
170 * @param[out] u8 results = The response route node
171 * ---------------------------------------------------------------------------------------
172 */
173u8 graphGetRsp(u8 *graph, u8 nodeA, u8 nodeB)
174{
175 u8 size = graph[0];
176 ASSERT(size <= MAX_NODES);
177 ASSERT((nodeA < size) && (nodeB < size));
178 return (graph[1+(nodeA*size+nodeB)*2+1] & 0xF0)>>4;
179}
180
181/*----------------------------------------------------------------------------------------
182 * u8
183 * graphGetReq(u8 *graph, u8 nodeA, u8 nodeB)
184 *
185 * Description:
186 * Returns the graph node used by nodeA to route requests targeted at nodeB.
187 * This will be a node directly connected to nodeA (possibly nodeB itself),
188 * or "Route to Self" if nodeA and nodeB are the same node.
189 * Note that all node numbers are abstract node numbers of the topology graph,
190 * it is the responsibility of the caller to apply any permutation needed.
191 *
192 * Parameters:
193 * @param[in] u8 graph = the graph to examine
194 * @param[in] u8 nodeA = the node number of the first node
195 * @param[in] u8 nodeB = the node number of the second node
196 * @param[out] u8 results = The request route node
197 * ---------------------------------------------------------------------------------------
198 */
199u8 graphGetReq(u8 *graph, u8 nodeA, u8 nodeB)
200{
Marc Jones212486e2008-07-17 19:50:37 +0000201 u8 size = graph[0];
Marc Jones8ae8c882007-12-19 01:32:08 +0000202 ASSERT(size <= MAX_NODES);
203 ASSERT((nodeA < size) && (nodeB < size));
204 return (graph[1+(nodeA*size+nodeB)*2+1] & 0x0F);
205}
206
207/*----------------------------------------------------------------------------------------
208 * u8
Marc Jones212486e2008-07-17 19:50:37 +0000209 * graphGetBc(u8 *graph, u8 nodeA, u8 nodeB)
Marc Jones8ae8c882007-12-19 01:32:08 +0000210 *
211 * Description:
212 * Returns a bit vector of nodes that nodeA should forward a broadcast from
213 * nodeB towards
214 *
215 * Parameters:
216 * @param[in] u8 graph = the graph to examine
217 * @param[in] u8 nodeA = the node number of the first node
218 * @param[in] u8 nodeB = the node number of the second node
219 * OU u8 results = the broadcast routes for nodeA from nodeB
220 * ---------------------------------------------------------------------------------------
221 */
Marc Jones212486e2008-07-17 19:50:37 +0000222u8 graphGetBc(u8 *graph, u8 nodeA, u8 nodeB)
Marc Jones8ae8c882007-12-19 01:32:08 +0000223{
Marc Jones212486e2008-07-17 19:50:37 +0000224 u8 size = graph[0];
Marc Jones8ae8c882007-12-19 01:32:08 +0000225 ASSERT(size <= MAX_NODES);
226 ASSERT((nodeA < size) && (nodeB < size));
227 return graph[1+(nodeA*size+nodeB)*2];
228}
229
230
231/***************************************************************************
232 *** GENERIC HYPERTRANSPORT DISCOVERY CODE ***
233 ***************************************************************************/
234
235/*----------------------------------------------------------------------------------------
236 * void
237 * routeFromBSP(u8 targetNode, u8 actualTarget, sMainData *pDat)
238 *
239 * Description:
240 * Ensure a request / response route from target node to bsp. Since target node is
241 * always a predecessor of actual target node, each node gets a route to actual target
242 * on the link that goes to target. The routing produced by this routine is adequate
243 * for config access during discovery, but NOT for coherency.
244 *
245 * Parameters:
246 * @param[in] u8 targetNode = the path to actual target goes through target
247 * @param[in] u8 actualTarget = the ultimate target being routed to
248 * @param[in] sMainData* pDat = our global state, port config info
249 * ---------------------------------------------------------------------------------------
250 */
251void routeFromBSP(u8 targetNode, u8 actualTarget, sMainData *pDat)
252{
253 u8 predecessorNode, predecessorLink, currentPair;
254
255 if (targetNode == 0)
Marc Jonesaee07962008-07-16 21:09:31 +0000256 return; /* BSP has no predecessor, stop */
Marc Jones8ae8c882007-12-19 01:32:08 +0000257
Marc Jonesaee07962008-07-16 21:09:31 +0000258 /* Search for the link that connects targetNode to its predecessor */
Marc Jones8ae8c882007-12-19 01:32:08 +0000259 currentPair = 0;
260 while (pDat->PortList[currentPair*2+1].NodeID != targetNode)
261 {
262 currentPair++;
263 ASSERT(currentPair < pDat->TotalLinks);
264 }
265
266 predecessorNode = pDat->PortList[currentPair*2].NodeID;
267 predecessorLink = pDat->PortList[currentPair*2].Link;
268
Marc Jonesaee07962008-07-16 21:09:31 +0000269 /* Recursively call self to ensure the route from the BSP to the Predecessor */
270 /* Node is established */
Marc Jones8ae8c882007-12-19 01:32:08 +0000271 routeFromBSP(predecessorNode, actualTarget, pDat);
272
273 pDat->nb->writeRoutingTable(predecessorNode, actualTarget, predecessorLink, pDat->nb);
274}
275
276/*----------------------------------------------------------------------------------------
277 * u8
278 * convertNodeToLink(u8 srcNode, u8 targetNode, sMainData *pDat)
279 *
280 * Description:
281 * Return the link on source node which connects to target node
282 *
283 * Parameters:
284 * @param[in] u8 srcNode = the source node
285 * @param[in] u8 targetNode = the target node to find the link to
286 * @param[in] sMainData* pDat = our global state
287 * @param[out] u8 results = the link on source which connects to target
288 * ---------------------------------------------------------------------------------------
289 */
290u8 convertNodeToLink(u8 srcNode, u8 targetNode, sMainData *pDat)
291{
292 u8 targetlink = INVALID_LINK;
293 u8 k;
294
295 for (k = 0; k < pDat->TotalLinks*2; k += 2)
296 {
297 if ((pDat->PortList[k+0].NodeID == srcNode) && (pDat->PortList[k+1].NodeID == targetNode))
298 {
299 targetlink = pDat->PortList[k+0].Link;
300 break;
301 }
302 else if ((pDat->PortList[k+1].NodeID == srcNode) && (pDat->PortList[k+0].NodeID == targetNode))
303 {
304 targetlink = pDat->PortList[k+1].Link;
305 break;
306 }
307 }
308 ASSERT(targetlink != INVALID_LINK);
309
310 return targetlink;
311}
312
313
314/*----------------------------------------------------------------------------------------
315 * void
316 * htDiscoveryFloodFill(sMainData *pDat)
317 *
318 * Description:
319 * Discover all coherent devices in the system, initializing some basics like node IDs
320 * and total nodes found in the process. As we go we also build a representation of the
321 * discovered system which we will use later to program the routing tables. During this
322 * step, the routing is via default link back to BSP and to each new node on the link it
323 * was discovered on (no coherency is active yet).
324 *
325 * Parameters:
326 * @param[in] sMainData* pDat = our global state
327 * ---------------------------------------------------------------------------------------
328 */
329void htDiscoveryFloodFill(sMainData *pDat)
330{
331 u8 currentNode = 0;
332 u8 currentLink;
333
334 /* Entries are always added in pairs, the even indices are the 'source'
335 * side closest to the BSP, the odd indices are the 'destination' side
336 */
337
338 while (currentNode <= pDat->NodesDiscovered)
339 {
340 u32 temp;
341
342 if (currentNode != 0)
343 {
344 /* Set path from BSP to currentNode */
345 routeFromBSP(currentNode, currentNode, pDat);
346
347 /* Set path from BSP to currentNode for currentNode+1 if
348 * currentNode+1 != MAX_NODES
349 */
350 if (currentNode+1 != MAX_NODES)
351 routeFromBSP(currentNode, currentNode+1, pDat);
352
353 /* Configure currentNode to route traffic to the BSP through its
354 * default link
355 */
356 pDat->nb->writeRoutingTable(currentNode, 0, pDat->nb->readDefLnk(currentNode, pDat->nb), pDat->nb);
357 }
358
359 /* Set currentNode's NodeID field to currentNode */
360 pDat->nb->writeNodeID(currentNode, currentNode, pDat->nb);
361
362 /* Enable routing tables on currentNode*/
363 pDat->nb->enableRoutingTables(currentNode, pDat->nb);
364
365 for (currentLink = 0; currentLink < pDat->nb->maxLinks; currentLink++)
366 {
367 BOOL linkfound;
368 u8 token;
369
370 if (pDat->HtBlock->AMD_CB_IgnoreLink && pDat->HtBlock->AMD_CB_IgnoreLink(currentNode, currentLink))
371 continue;
372
373 if (pDat->nb->readTrueLinkFailStatus(currentNode, currentLink, pDat, pDat->nb))
374 continue;
375
376 /* Make sure that the link is connected, coherent, and ready */
377 if (!pDat->nb->verifyLinkIsCoherent(currentNode, currentLink, pDat->nb))
378 continue;
379
380
381 /* Test to see if the currentLink has already been explored */
382 linkfound = FALSE;
383 for (temp = 0; temp < pDat->TotalLinks; temp++)
384 {
385 if ((pDat->PortList[temp*2+1].NodeID == currentNode) &&
386 (pDat->PortList[temp*2+1].Link == currentLink))
387 {
388 linkfound = TRUE;
389 break;
390 }
391 }
392 if (linkfound)
393 {
394 /* We had already expored this link */
395 continue;
396 }
397
398 if (pDat->nb->handleSpecialLinkCase(currentNode, currentLink, pDat, pDat->nb))
399 {
400 continue;
401 }
402
403 /* Modify currentNode's routing table to use currentLink to send
404 * traffic to currentNode+1
405 */
406 pDat->nb->writeRoutingTable(currentNode, currentNode+1, currentLink, pDat->nb);
407
408 /* Check the northbridge of the node we just found, to make sure it is compatible
409 * before doing anything else to it.
410 */
411 if (!pDat->nb->isCompatible(currentNode+1, pDat->nb))
412 {
413 u8 nodeToKill;
414
415 /* Notify BIOS of event (while variables are still the same) */
416 if (pDat->HtBlock->AMD_CB_EventNotify)
417 {
Marc Jones212486e2008-07-17 19:50:37 +0000418 sHtEventCohFamilyFeud evt;
419 evt.eSize = sizeof(sHtEventCohFamilyFeud);
420 evt.node = currentNode;
421 evt.link = currentLink;
422 evt.totalNodes = pDat->NodesDiscovered;
Marc Jones8ae8c882007-12-19 01:32:08 +0000423
424 pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_ERROR,
425 HT_EVENT_COH_FAMILY_FEUD,
426 (u8 *)&evt);
427 }
428
429 /* If node is not compatible, force boot to 1P
430 * If they are not compatible stop cHT init and:
431 * 1. Disable all cHT links on the BSP
432 * 2. Configure the BSP routing tables as a UP.
433 * 3. Notify main BIOS.
434 */
435 pDat->NodesDiscovered = 0;
436 currentNode = 0;
437 pDat->TotalLinks = 0;
438 /* Abandon our coherent link data structure. At this point there may
439 * be coherent links on the BSP that are not yet in the portList, and
440 * we have to turn them off anyway. So depend on the hardware to tell us.
441 */
442 for (currentLink = 0; currentLink < pDat->nb->maxLinks; currentLink++)
443 {
444 /* Stop all links which are connected, coherent, and ready */
445 if (pDat->nb->verifyLinkIsCoherent(currentNode, currentLink, pDat->nb))
446 pDat->nb->stopLink(currentNode, currentLink, pDat->nb);
447 }
448
449 for (nodeToKill = 0; nodeToKill < pDat->nb->maxNodes; nodeToKill++)
450 {
451 pDat->nb->writeFullRoutingTable(0, nodeToKill, ROUTETOSELF, ROUTETOSELF, 0, pDat->nb);
452 }
453
454 /* End Coherent Discovery */
455 STOP_HERE;
456 break;
457 }
458
459 /* Read token from Current+1 */
460 token = pDat->nb->readToken(currentNode+1, pDat->nb);
461 ASSERT(token <= pDat->NodesDiscovered);
462 if (token == 0)
463 {
464 pDat->NodesDiscovered++;
465 ASSERT(pDat->NodesDiscovered < pDat->nb->maxNodes);
466 /* Check the capability of northbridges against the currently known configuration */
467 if (!pDat->nb->isCapable(currentNode+1, pDat, pDat->nb))
468 {
469 u8 nodeToKill;
470
471 /* Notify BIOS of event */
472 if (pDat->HtBlock->AMD_CB_EventNotify)
473 {
Marc Jones212486e2008-07-17 19:50:37 +0000474 sHtEventCohMpCapMismatch evt;
475 evt.eSize = sizeof(sHtEventCohMpCapMismatch);
476 evt.node = currentNode;
477 evt.link = currentLink;
478 evt.sysMpCap = pDat->sysMpCap;
479 evt.totalNodes = pDat->NodesDiscovered;
Marc Jones8ae8c882007-12-19 01:32:08 +0000480
481 pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_ERROR,
482 HT_EVENT_COH_MPCAP_MISMATCH,
483 (u8 *)&evt);
484 }
485
486 pDat->NodesDiscovered = 0;
487 currentNode = 0;
488 pDat->TotalLinks = 0;
489
490 for (nodeToKill = 0; nodeToKill < pDat->nb->maxNodes; nodeToKill++)
491 {
492 pDat->nb->writeFullRoutingTable(0, nodeToKill, ROUTETOSELF, ROUTETOSELF, 0, pDat->nb);
493 }
494
495 /* End Coherent Discovery */
496 STOP_HERE;
497 break;
498 }
499
500 token = pDat->NodesDiscovered;
501 pDat->nb->writeToken(currentNode+1, token, pDat->nb);
502 /* Inform that we have discovered a node, so that logical id to
503 * socket mapping info can be recorded.
504 */
505 if (pDat->HtBlock->AMD_CB_EventNotify)
506 {
Marc Jones212486e2008-07-17 19:50:37 +0000507 sHtEventCohNodeDiscovered evt;
508 evt.eSize = sizeof(sHtEventCohNodeDiscovered);
509 evt.node = currentNode;
510 evt.link = currentLink;
511 evt.newNode = token;
Marc Jones8ae8c882007-12-19 01:32:08 +0000512
513 pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_INFO,
514 HT_EVENT_COH_NODE_DISCOVERED,
515 (u8 *)&evt);
516 }
517 }
518
519 if (pDat->TotalLinks == MAX_PLATFORM_LINKS)
520 {
521 /*
522 * Exceeded our capacity to describe all coherent links found in the system.
523 * Error strategy:
524 * Auto recovery is not possible because data space is already all used.
525 * If the callback is not implemented or returns we will continue to initialize
526 * the fabric we are capable of representing, adding no more nodes or links.
527 * This should yield a bootable topology, but likely not the one intended.
528 * We cannot continue discovery, there may not be any way to route a new
529 * node back to the BSP if we can't add links to our representation of the system.
530 */
531 if (pDat->HtBlock->AMD_CB_EventNotify)
532 {
Marc Jones212486e2008-07-17 19:50:37 +0000533 sHtEventCohLinkExceed evt;
534 evt.eSize = sizeof(sHtEventCohLinkExceed);
535 evt.node = currentNode;
536 evt.link = currentLink;
537 evt.targetNode = token;
538 evt.totalNodes = pDat->NodesDiscovered;
539 evt.maxLinks = pDat->nb->maxLinks;
Marc Jones8ae8c882007-12-19 01:32:08 +0000540
541 pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_ERROR,
542 HT_EVENT_COH_LINK_EXCEED,
543 (u8 *)&evt);
544 }
545 /* Force link and node loops to halt */
546 STOP_HERE;
547 currentNode = pDat->NodesDiscovered;
548 break;
549 }
550
551 pDat->PortList[pDat->TotalLinks*2].Type = PORTLIST_TYPE_CPU;
552 pDat->PortList[pDat->TotalLinks*2].Link = currentLink;
553 pDat->PortList[pDat->TotalLinks*2].NodeID = currentNode;
554
555 pDat->PortList[pDat->TotalLinks*2+1].Type = PORTLIST_TYPE_CPU;
556 pDat->PortList[pDat->TotalLinks*2+1].Link = pDat->nb->readDefLnk(currentNode+1, pDat->nb);
557 pDat->PortList[pDat->TotalLinks*2+1].NodeID = token;
558
559 pDat->TotalLinks++;
560
561 if ( !pDat->sysMatrix[currentNode][token] )
562 {
563 pDat->sysDegree[currentNode]++;
564 pDat->sysDegree[token]++;
565 pDat->sysMatrix[currentNode][token] = TRUE;
566 pDat->sysMatrix[token][currentNode] = TRUE;
567 }
568 }
569 currentNode++;
570 }
571}
572
573
574/***************************************************************************
575 *** ISOMORPHISM BASED ROUTING TABLE GENERATION CODE ***
576 ***************************************************************************/
577
578/*----------------------------------------------------------------------------------------
579 * BOOL
580 * isoMorph(u8 i, sMainData *pDat)
581 *
582 * Description:
583 * Is graphA isomorphic to graphB?
584 * if this function returns true, then Perm will contain the permutation
585 * required to transform graphB into graphA.
586 * We also use the degree of each node, that is the number of connections it has, to
587 * speed up rejection of non-isomorphic graphs (if there is a node in graphA with n
588 * connections, there must be at least one unmatched in graphB with n connections).
589 *
590 * Parameters:
591 * @param[in] u8 i = the discovered node which we are trying to match
592 * with a permutation the topology
593 * @param[in]/@param[out] sMainData* pDat = our global state, degree and adjacency matrix,
594 * output a permutation if successful
595 * @param[out] BOOL results = the graphs are (or are not) isomorphic
596 * ---------------------------------------------------------------------------------------
597 */
598BOOL isoMorph(u8 i, sMainData *pDat)
599{
600 u8 j, k;
601 u8 nodecnt;
602
603 /* We have only been called if nodecnt == pSelected->size ! */
604 nodecnt = pDat->NodesDiscovered+1;
605
606 if (i != nodecnt)
607 {
Marc Jonesaee07962008-07-16 21:09:31 +0000608 /* Keep building the permutation */
Marc Jones8ae8c882007-12-19 01:32:08 +0000609 for (j = 0; j < nodecnt; j++)
610 {
Marc Jonesaee07962008-07-16 21:09:31 +0000611 /* Make sure the degree matches */
Marc Jones8ae8c882007-12-19 01:32:08 +0000612 if (pDat->sysDegree[i] != pDat->dbDegree[j])
613 continue;
614
Marc Jonesaee07962008-07-16 21:09:31 +0000615 /* Make sure that j hasn't been used yet (ought to use a "used" */
616 /* array instead, might be faster) */
Marc Jones8ae8c882007-12-19 01:32:08 +0000617 for (k = 0; k < i; k++)
618 {
619 if (pDat->Perm[k] == j)
620 break;
621 }
622 if (k != i)
623 continue;
624 pDat->Perm[i] = j;
625 if (isoMorph(i+1, pDat))
626 return TRUE;
627 }
628 return FALSE;
629 } else {
Marc Jonesaee07962008-07-16 21:09:31 +0000630 /* Test to see if the permutation is isomorphic */
Marc Jones8ae8c882007-12-19 01:32:08 +0000631 for (j = 0; j < nodecnt; j++)
632 {
633 for (k = 0; k < nodecnt; k++)
634 {
635 if ( pDat->sysMatrix[j][k] !=
636 pDat->dbMatrix[pDat->Perm[j]][pDat->Perm[k]] )
637 return FALSE;
638 }
639 }
640 return TRUE;
641 }
642}
643
644
645/*----------------------------------------------------------------------------------------
646 * void
647 * lookupComputeAndLoadRoutingTables(sMainData *pDat)
648 *
649 * Description:
650 * Using the description of the fabric topology we discovered, try to find a match
651 * among the supported topologies. A supported topology description matches
652 * the discovered fabric if the nodes can be matched in such a way that all the nodes connected
653 * in one set are exactly the nodes connected in the other (formally, that the graphs are
654 * isomorphic). Which links are used is not really important to matching. If the graphs
655 * match, then there is a permutation of one that translates the node positions and linkages
656 * to the other.
657 *
658 * In order to make the isomorphism test efficient, we test for matched number of nodes
659 * (a 4 node fabric is not isomorphic to a 2 node topology), and provide degrees of nodes
660 * to the isomorphism test.
661 *
662 * The generic routing table solution for any topology is predetermined and represented
663 * as part of the topology. The permutation we computed tells us how to interpret the
664 * routing onto the fabric we discovered. We do this working backward from the last
665 * node discovered to the BSP, writing the routing tables as we go.
666 *
667 * Parameters:
668 * @param[in] sMainData* pDat = our global state, the discovered fabric,
669 * @param[out] degree matrix, permutation
670 * ---------------------------------------------------------------------------------------
671 */
672void lookupComputeAndLoadRoutingTables(sMainData *pDat)
673{
674 u8 **pTopologyList;
675 u8 *pSelected;
676
677 int i, j, k, size;
678
679 size = pDat->NodesDiscovered + 1;
680 /* Use the provided topology list or the internal, default one. */
681 pTopologyList = pDat->HtBlock->topolist;
682 if (pTopologyList == NULL)
683 {
684 getAmdTopolist(&pTopologyList);
685 }
686
687 pSelected = *pTopologyList;
688 while (pSelected != NULL)
689 {
690 if (graphHowManyNodes(pSelected) == size)
691 {
Marc Jonesaee07962008-07-16 21:09:31 +0000692 /* Build Degree vector and Adjency Matrix for this entry */
Marc Jones8ae8c882007-12-19 01:32:08 +0000693 for (i = 0; i < size; i++)
694 {
695 pDat->dbDegree[i] = 0;
696 for (j = 0; j < size; j++)
697 {
698 if (graphIsAdjacent(pSelected, i, j))
699 {
700 pDat->dbMatrix[i][j] = 1;
701 pDat->dbDegree[i]++;
702 }
703 else
704 {
705 pDat->dbMatrix[i][j] = 0;
706 }
707 }
708 }
709 if (isoMorph(0, pDat))
Marc Jonesaee07962008-07-16 21:09:31 +0000710 break; /* A matching topology was found */
Marc Jones8ae8c882007-12-19 01:32:08 +0000711 }
712
713 pTopologyList++;
714 pSelected = *pTopologyList;
715 }
716
717 if (pSelected != NULL)
718 {
Marc Jonesaee07962008-07-16 21:09:31 +0000719 /* Compute the reverse Permutation */
Marc Jones8ae8c882007-12-19 01:32:08 +0000720 for (i = 0; i < size; i++)
721 {
722 pDat->ReversePerm[pDat->Perm[i]] = i;
723 }
724
Marc Jonesaee07962008-07-16 21:09:31 +0000725 /* Start with the last discovered node, and move towards the BSP */
Marc Jones8ae8c882007-12-19 01:32:08 +0000726 for (i = size-1; i >= 0; i--)
727 {
728 for (j = 0; j < size; j++)
729 {
730 u8 ReqTargetLink, RspTargetLink;
731 u8 ReqTargetNode, RspTargetNode;
732
733 u8 AbstractBcTargetNodes = graphGetBc(pSelected, pDat->Perm[i], pDat->Perm[j]);
734 u32 BcTargetLinks = 0;
735
736 for (k = 0; k < MAX_NODES; k++)
737 {
738 if (AbstractBcTargetNodes & ((u32)1<<k))
739 {
740 BcTargetLinks |= (u32)1 << convertNodeToLink(i, pDat->ReversePerm[k], pDat);
741 }
742 }
743
744 if (i == j)
745 {
746 ReqTargetLink = ROUTETOSELF;
747 RspTargetLink = ROUTETOSELF;
748 }
749 else
750 {
751 ReqTargetNode = graphGetReq(pSelected, pDat->Perm[i], pDat->Perm[j]);
752 ReqTargetLink = convertNodeToLink(i, pDat->ReversePerm[ReqTargetNode], pDat);
753
754 RspTargetNode = graphGetRsp(pSelected, pDat->Perm[i], pDat->Perm[j]);
755 RspTargetLink = convertNodeToLink(i, pDat->ReversePerm[RspTargetNode], pDat);
756 }
757
758 pDat->nb->writeFullRoutingTable(i, j, ReqTargetLink, RspTargetLink, BcTargetLinks, pDat->nb);
759 }
760 /* Clean up discovery 'footprint' that otherwise remains in the routing table. It didn't hurt
761 * anything, but might cause confusion during debug and validation. Do this by setting the
762 * route back to all self routes. Since it's the node that would be one more than actually installed,
763 * this only applies if less than maxNodes were found.
764 */
765 if (size < pDat->nb->maxNodes)
766 {
767 pDat->nb->writeFullRoutingTable(i, size, ROUTETOSELF, ROUTETOSELF, 0, pDat->nb);
768 }
769 }
770
771 }
772 else
773 {
774 /*
775 * No Matching Topology was found
776 * Error Strategy:
777 * Auto recovery doesn't seem likely, Force boot as 1P.
778 * For reporting, logging, provide number of nodes
779 * If not implemented or returns, boot as BSP uniprocessor.
780 */
781 if (pDat->HtBlock->AMD_CB_EventNotify)
782 {
Marc Jones212486e2008-07-17 19:50:37 +0000783 sHtEventCohNoTopology evt;
784 evt.eSize = sizeof(sHtEventCohNoTopology);
785 evt.totalNodes = pDat->NodesDiscovered;
Marc Jones8ae8c882007-12-19 01:32:08 +0000786
787 pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_ERROR,
788 HT_EVENT_COH_NO_TOPOLOGY,
789 (u8 *)&evt);
790 }
791 STOP_HERE;
792 /* Force 1P */
793 pDat->NodesDiscovered = 0;
794 pDat->TotalLinks = 0;
795 pDat->nb->enableRoutingTables(0, pDat->nb);
796 }
797}
798#endif /* HT_BUILD_NC_ONLY */
799
800
801/*----------------------------------------------------------------------------------------
802 * void
803 * finializeCoherentInit(sMainData *pDat)
804 *
805 * Description:
806 * Find the total number of cores and update the number of nodes and cores in all cpus.
807 * Limit cpu config access to installed cpus.
808 *
809 * Parameters:
810 * @param[in] sMainData* pDat = our global state, number of nodes discovered.
811 * ---------------------------------------------------------------------------------------
812 */
813void finializeCoherentInit(sMainData *pDat)
814{
815 u8 curNode;
816
817 u8 totalCores = 0;
818 for (curNode = 0; curNode < pDat->NodesDiscovered+1; curNode++)
819 {
820 totalCores += pDat->nb->getNumCoresOnNode(curNode, pDat->nb);
821 }
822
823 for (curNode = 0; curNode < pDat->NodesDiscovered+1; curNode++)
824 {
825 pDat->nb->setTotalNodesAndCores(curNode, pDat->NodesDiscovered+1, totalCores, pDat->nb);
826 }
827
828 for (curNode = 0; curNode < pDat->NodesDiscovered+1; curNode++)
829 {
830 pDat->nb->limitNodes(curNode, pDat->nb);
831 }
832
833}
834
835/*----------------------------------------------------------------------------------------
836 * void
837 * coherentInit(sMainData *pDat)
838 *
839 * Description:
840 * Perform discovery and initialization of the coherent fabric.
841 *
842 * Parameters:
843 * @param[in] sMainData* pDat = our global state
844 * ---------------------------------------------------------------------------------------
845 */
846void coherentInit(sMainData *pDat)
847{
Marc Jones212486e2008-07-17 19:50:37 +0000848 u8 i, j;
Marc Jones8ae8c882007-12-19 01:32:08 +0000849
850#ifdef HT_BUILD_NC_ONLY
851 /* Replace discovery process with:
852 * No other nodes, no coherent links
853 * Enable routing tables on currentNode, for power on self route
854 */
855 pDat->NodesDiscovered = 0;
856 pDat->TotalLinks = 0;
857 pDat->nb->enableRoutingTables(0, pDat->nb);
858#else
859 pDat->NodesDiscovered = 0;
860 pDat->TotalLinks = 0;
861 for (i = 0; i < MAX_NODES; i++)
862 {
863 pDat->sysDegree[i] = 0;
864 for (j = 0; j < MAX_NODES; j++)
865 {
866 pDat->sysMatrix[i][j] = 0;
867 }
868 }
869
870 htDiscoveryFloodFill(pDat);
871 lookupComputeAndLoadRoutingTables(pDat);
872#endif
873 finializeCoherentInit(pDat);
874}
875
876/***************************************************************************
877 *** Non-coherent init code ***
878 *** Algorithms ***
879 ***************************************************************************/
880/*----------------------------------------------------------------------------------------
881 * void
882 * processLink(u8 node, u8 link, sMainData *pDat)
883 *
884 * Description:
885 * Process a non-coherent link, enabling a range of bus numbers, and setting the device
886 * ID for all devices found
887 *
888 * Parameters:
889 * @param[in] u8 node = Node on which to process nc init
890 * @param[in] u8 link = The non-coherent link on that node
891 * @param[in] sMainData* pDat = our global state
892 * ---------------------------------------------------------------------------------------
893 */
894void processLink(u8 node, u8 link, sMainData *pDat)
895{
896 u8 secBus, subBus;
897 u32 currentBUID;
898 u32 temp;
899 u32 unitIDcnt;
900 SBDFO currentPtr;
901 u8 depth;
902 u8 *pSwapPtr;
903
904 SBDFO lastSBDFO = ILLEGAL_SBDFO;
905 u8 lastLink = 0;
906
907 ASSERT(node < pDat->nb->maxNodes && link < pDat->nb->maxLinks);
908
909 if ((pDat->HtBlock->AMD_CB_OverrideBusNumbers == NULL)
910 || !pDat->HtBlock->AMD_CB_OverrideBusNumbers(node, link, &secBus, &subBus))
911 {
912 /* Assign Bus numbers */
913 if (pDat->AutoBusCurrent >= pDat->HtBlock->AutoBusMax)
914 {
915 /* If we run out of Bus Numbers notify, if call back unimplemented or if it
916 * returns, skip this chain
917 */
918 if (pDat->HtBlock->AMD_CB_EventNotify)
919 {
Marc Jones212486e2008-07-17 19:50:37 +0000920 sHTEventNcohBusMaxExceed evt;
921 evt.eSize = sizeof(sHTEventNcohBusMaxExceed);
922 evt.node = node;
923 evt.link = link;
924 evt.bus = pDat->AutoBusCurrent;
Marc Jones8ae8c882007-12-19 01:32:08 +0000925
926 pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_ERROR,HT_EVENT_NCOH_BUS_MAX_EXCEED,(u8 *)&evt);
927 }
928 STOP_HERE;
929 return;
930 }
931
932 if (pDat->UsedCfgMapEntires >= 4)
933 {
934 /* If we have used all the PCI Config maps we can't add another chain.
935 * Notify and if call back is unimplemented or returns, skip this chain.
936 */
937 if (pDat->HtBlock->AMD_CB_EventNotify)
938 {
Marc Jones212486e2008-07-17 19:50:37 +0000939 sHtEventNcohCfgMapExceed evt;
940 evt.eSize = sizeof(sHtEventNcohCfgMapExceed);
941 evt.node = node;
942 evt.link = link;
Marc Jones8ae8c882007-12-19 01:32:08 +0000943
944 pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_ERROR,
945 HT_EVENT_NCOH_CFG_MAP_EXCEED,
946 (u8 *)&evt);
947 }
948 STOP_HERE;
949 return;
950 }
951
952 secBus = pDat->AutoBusCurrent;
953 subBus = secBus + pDat->HtBlock->AutoBusIncrement-1;
954 pDat->AutoBusCurrent += pDat->HtBlock->AutoBusIncrement;
955 }
956
957 pDat->nb->setCFGAddrMap(pDat->UsedCfgMapEntires, secBus, subBus, node, link, pDat, pDat->nb);
958 pDat->UsedCfgMapEntires++;
959
960 if ((pDat->HtBlock->AMD_CB_ManualBUIDSwapList != NULL)
961 && pDat->HtBlock->AMD_CB_ManualBUIDSwapList(node, link, &pSwapPtr))
962 {
963 /* Manual non-coherent BUID assignment */
964
965 /* Assign BUID's per manual override */
966 while (*pSwapPtr != 0xFF)
967 {
968 currentPtr = MAKE_SBDFO(0, secBus, *pSwapPtr, 0, 0);
969 pSwapPtr++;
970
971 do
972 {
973 AmdPCIFindNextCap(&currentPtr);
974 ASSERT(currentPtr != ILLEGAL_SBDFO);
975 AmdPCIRead(currentPtr, &temp);
976 } while (!IS_HT_SLAVE_CAPABILITY(temp));
977
978 currentBUID = *pSwapPtr;
979 pSwapPtr++;
980 AmdPCIWriteBits(currentPtr, 20, 16, &currentBUID);
981 }
982
983 /* Build chain of devices */
984 depth = 0;
985 pSwapPtr++;
986 while (*pSwapPtr != 0xFF)
987 {
988 pDat->PortList[pDat->TotalLinks*2].NodeID = node;
989 if (depth == 0)
990 {
991 pDat->PortList[pDat->TotalLinks*2].Type = PORTLIST_TYPE_CPU;
992 pDat->PortList[pDat->TotalLinks*2].Link = link;
993 }
994 else
995 {
996 pDat->PortList[pDat->TotalLinks*2].Type = PORTLIST_TYPE_IO;
997 pDat->PortList[pDat->TotalLinks*2].Link = 1-lastLink;
998 pDat->PortList[pDat->TotalLinks*2].HostLink = link;
999 pDat->PortList[pDat->TotalLinks*2].HostDepth = depth-1;
1000 pDat->PortList[pDat->TotalLinks*2].Pointer = lastSBDFO;
1001 }
1002
1003 pDat->PortList[pDat->TotalLinks*2+1].Type = PORTLIST_TYPE_IO;
1004 pDat->PortList[pDat->TotalLinks*2+1].NodeID = node;
1005 pDat->PortList[pDat->TotalLinks*2+1].HostLink = link;
1006 pDat->PortList[pDat->TotalLinks*2+1].HostDepth = depth;
1007
1008 currentPtr = MAKE_SBDFO(0, secBus, (*pSwapPtr & 0x3F), 0, 0);
1009 do
1010 {
1011 AmdPCIFindNextCap(&currentPtr);
1012 ASSERT(currentPtr != ILLEGAL_SBDFO);
1013 AmdPCIRead(currentPtr, &temp);
1014 } while (!IS_HT_SLAVE_CAPABILITY(temp));
1015 pDat->PortList[pDat->TotalLinks*2+1].Pointer = currentPtr;
1016 lastSBDFO = currentPtr;
1017
1018 /* Bit 6 indicates whether orientation override is desired.
1019 * Bit 7 indicates the upstream link if overriding.
1020 */
1021 /* assert catches at least the one known incorrect setting */
1022 ASSERT ((*pSwapPtr & 0x40) || (!(*pSwapPtr & 0x80)));
1023 if (*pSwapPtr & 0x40)
1024 {
1025 /* Override the device's orientation */
1026 lastLink = *pSwapPtr >> 7;
1027 }
1028 else
1029 {
1030 /* Detect the device's orientation */
1031 AmdPCIReadBits(currentPtr, 26, 26, &temp);
1032 lastLink = (u8)temp;
1033 }
1034 pDat->PortList[pDat->TotalLinks*2+1].Link = lastLink;
1035
1036 depth++;
1037 pDat->TotalLinks++;
1038 pSwapPtr++;
1039 }
1040 }
1041 else
1042 {
1043 /* Automatic non-coherent device detection */
1044 depth = 0;
1045 currentBUID = 1;
1046 while (1)
1047 {
1048 currentPtr = MAKE_SBDFO(0, secBus, 0, 0, 0);
1049
1050 AmdPCIRead(currentPtr, &temp);
1051 if (temp == 0xFFFFFFFF)
1052 /* No device found at currentPtr */
1053 break;
1054
1055 if (pDat->TotalLinks == MAX_PLATFORM_LINKS)
1056 {
1057 /*
1058 * Exceeded our capacity to describe all non-coherent links found in the system.
1059 * Error strategy:
1060 * Auto recovery is not possible because data space is already all used.
1061 */
1062 if (pDat->HtBlock->AMD_CB_EventNotify)
1063 {
Marc Jones212486e2008-07-17 19:50:37 +00001064 sHtEventNcohLinkExceed evt;
1065 evt.eSize = sizeof(sHtEventNcohLinkExceed);
1066 evt.node = node;
1067 evt.link = link;
1068 evt.depth = depth;
1069 evt.maxLinks = pDat->nb->maxLinks;
Marc Jones8ae8c882007-12-19 01:32:08 +00001070
1071 pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_ERROR,
1072 HT_EVENT_NCOH_LINK_EXCEED,
1073 (u8 *)&evt);
1074 }
1075 /* Force link loop to halt */
1076 STOP_HERE;
1077 break;
1078 }
1079
1080 pDat->PortList[pDat->TotalLinks*2].NodeID = node;
1081 if (depth == 0)
1082 {
1083 pDat->PortList[pDat->TotalLinks*2].Type = PORTLIST_TYPE_CPU;
1084 pDat->PortList[pDat->TotalLinks*2].Link = link;
1085 }
1086 else
1087 {
1088 pDat->PortList[pDat->TotalLinks*2].Type = PORTLIST_TYPE_IO;
1089 pDat->PortList[pDat->TotalLinks*2].Link = 1-lastLink;
1090 pDat->PortList[pDat->TotalLinks*2].HostLink = link;
1091 pDat->PortList[pDat->TotalLinks*2].HostDepth = depth-1;
1092 pDat->PortList[pDat->TotalLinks*2].Pointer = lastSBDFO;
1093 }
1094
1095 pDat->PortList[pDat->TotalLinks*2+1].Type = PORTLIST_TYPE_IO;
1096 pDat->PortList[pDat->TotalLinks*2+1].NodeID = node;
1097 pDat->PortList[pDat->TotalLinks*2+1].HostLink = link;
1098 pDat->PortList[pDat->TotalLinks*2+1].HostDepth = depth;
1099
1100 do
1101 {
1102 AmdPCIFindNextCap(&currentPtr);
1103 ASSERT(currentPtr != ILLEGAL_SBDFO);
1104 AmdPCIRead(currentPtr, &temp);
1105 } while (!IS_HT_SLAVE_CAPABILITY(temp));
1106
1107 AmdPCIReadBits(currentPtr, 25, 21, &unitIDcnt);
1108 if ((unitIDcnt + currentBUID > 31) || ((secBus == 0) && (unitIDcnt + currentBUID > 24)))
1109 {
1110 /* An error handler for the case where we run out of BUID's on a chain */
1111 if (pDat->HtBlock->AMD_CB_EventNotify)
1112 {
Marc Jones212486e2008-07-17 19:50:37 +00001113 sHtEventNcohBuidExceed evt;
1114 evt.eSize = sizeof(sHtEventNcohBuidExceed);
1115 evt.node = node;
1116 evt.link = link;
1117 evt.depth = depth;
1118 evt.currentBUID = (uint8)currentBUID;
1119 evt.unitCount = (uint8)unitIDcnt;
Marc Jones8ae8c882007-12-19 01:32:08 +00001120
1121 pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_ERROR,HT_EVENT_NCOH_BUID_EXCEED,(u8 *)&evt);
1122 }
1123 STOP_HERE;
1124 break;
1125 }
1126 AmdPCIWriteBits(currentPtr, 20, 16, &currentBUID);
1127
1128
1129 currentPtr += MAKE_SBDFO(0, 0, currentBUID, 0, 0);
1130 AmdPCIReadBits(currentPtr, 20, 16, &temp);
1131 if (temp != currentBUID)
1132 {
1133 /* An error handler for this critical error */
1134 if (pDat->HtBlock->AMD_CB_EventNotify)
1135 {
Marc Jones212486e2008-07-17 19:50:37 +00001136 sHtEventNcohDeviceFailed evt;
1137 evt.eSize = sizeof(sHtEventNcohDeviceFailed);
1138 evt.node = node;
1139 evt.link = link;
1140 evt.depth = depth;
1141 evt.attemptedBUID = (uint8)currentBUID;
Marc Jones8ae8c882007-12-19 01:32:08 +00001142
1143 pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_ERROR,HT_EVENT_NCOH_DEVICE_FAILED,(u8 *)&evt);
1144 }
1145 STOP_HERE;
1146 break;
1147 }
1148
1149 AmdPCIReadBits(currentPtr, 26, 26, &temp);
1150 pDat->PortList[pDat->TotalLinks*2+1].Link = (u8)temp;
1151 pDat->PortList[pDat->TotalLinks*2+1].Pointer = currentPtr;
1152
1153 lastLink = (u8)temp;
1154 lastSBDFO = currentPtr;
1155
1156 depth++;
1157 pDat->TotalLinks++;
1158 currentBUID += unitIDcnt;
1159 }
1160 if (pDat->HtBlock->AMD_CB_EventNotify)
1161 {
1162 /* Provide information on automatic device results */
Marc Jones212486e2008-07-17 19:50:37 +00001163 sHtEventNcohAutoDepth evt;
1164 evt.eSize = sizeof(sHtEventNcohAutoDepth);
1165 evt.node = node;
1166 evt.link = link;
1167 evt.depth = (depth - 1);
Marc Jones8ae8c882007-12-19 01:32:08 +00001168
1169 pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_INFO,HT_EVENT_NCOH_AUTO_DEPTH,(u8 *)&evt);
1170 }
1171 }
1172}
1173
1174
1175/*----------------------------------------------------------------------------------------
1176 * void
1177 * ncInit(sMainData *pDat)
1178 *
1179 * Description:
1180 * Initialize the non-coherent fabric. Begin with the compat link on the BSP, then
1181 * find and initialize all other non-coherent chains.
1182 *
1183 * Parameters:
1184 * @param[in] sMainData* pDat = our global state
1185 * ---------------------------------------------------------------------------------------
1186 */
1187void ncInit(sMainData *pDat)
1188{
1189 u8 node, link;
1190 u8 compatLink;
1191
1192 compatLink = pDat->nb->readSbLink(pDat->nb);
1193 processLink(0, compatLink, pDat);
1194
1195 for (node = 0; node <= pDat->NodesDiscovered; node++)
1196 {
1197 for (link = 0; link < pDat->nb->maxLinks; link++)
1198 {
1199 if (pDat->HtBlock->AMD_CB_IgnoreLink && pDat->HtBlock->AMD_CB_IgnoreLink(node, link))
Marc Jonesaee07962008-07-16 21:09:31 +00001200 continue; /* Skip the link */
Marc Jones8ae8c882007-12-19 01:32:08 +00001201
1202 if (node == 0 && link == compatLink)
1203 continue;
1204
1205 if (pDat->nb->readTrueLinkFailStatus(node, link, pDat, pDat->nb))
1206 continue;
1207
1208 if (pDat->nb->verifyLinkIsNonCoherent(node, link, pDat->nb))
1209 processLink(node, link, pDat);
1210 }
1211 }
1212}
1213
1214/***************************************************************************
1215 *** Link Optimization ***
1216 ***************************************************************************/
1217
1218/*----------------------------------------------------------------------------------------
1219 * void
1220 * regangLinks(sMainData *pDat)
1221 *
1222 * Description:
1223 * Test the sublinks of a link to see if they qualify to be reganged. If they do,
1224 * update the port list data to indicate that this should be done. Note that no
1225 * actual hardware state is changed in this routine.
1226 *
1227 * Parameters:
1228 * @param[in,out] sMainData* pDat = our global state
1229 * ---------------------------------------------------------------------------------------
1230 */
1231void regangLinks(sMainData *pDat)
1232{
1233#ifndef HT_BUILD_NC_ONLY
1234 u8 i, j;
1235 for (i = 0; i < pDat->TotalLinks*2; i += 2)
1236 {
Marc Jonesaee07962008-07-16 21:09:31 +00001237 ASSERT(pDat->PortList[i].Type < 2 && pDat->PortList[i].Link < pDat->nb->maxLinks); /* Data validation */
1238 ASSERT(pDat->PortList[i+1].Type < 2 && pDat->PortList[i+1].Link < pDat->nb->maxLinks); /* data validation */
1239 ASSERT(!(pDat->PortList[i].Type == PORTLIST_TYPE_IO && pDat->PortList[i+1].Type == PORTLIST_TYPE_CPU)); /* ensure src is closer to the bsp than dst */
Marc Jones8ae8c882007-12-19 01:32:08 +00001240
1241 /* Regang is false unless we pass all conditions below */
1242 pDat->PortList[i].SelRegang = FALSE;
1243 pDat->PortList[i+1].SelRegang = FALSE;
1244
1245 if ( (pDat->PortList[i].Type != PORTLIST_TYPE_CPU) || (pDat->PortList[i+1].Type != PORTLIST_TYPE_CPU))
Marc Jonesaee07962008-07-16 21:09:31 +00001246 continue; /* Only process cpu to cpu links */
Marc Jones8ae8c882007-12-19 01:32:08 +00001247
1248 for (j = i+2; j < pDat->TotalLinks*2; j += 2)
1249 {
1250 if ( (pDat->PortList[j].Type != PORTLIST_TYPE_CPU) || (pDat->PortList[j+1].Type != PORTLIST_TYPE_CPU) )
Marc Jonesaee07962008-07-16 21:09:31 +00001251 continue; /* Only process cpu to cpu links */
Marc Jones8ae8c882007-12-19 01:32:08 +00001252
1253 if (pDat->PortList[i].NodeID != pDat->PortList[j].NodeID)
Marc Jonesaee07962008-07-16 21:09:31 +00001254 continue; /* Links must be from the same source */
Marc Jones8ae8c882007-12-19 01:32:08 +00001255
1256 if (pDat->PortList[i+1].NodeID != pDat->PortList[j+1].NodeID)
Marc Jonesaee07962008-07-16 21:09:31 +00001257 continue; /* Link must be to the same target */
Marc Jones8ae8c882007-12-19 01:32:08 +00001258
1259 if ((pDat->PortList[i].Link & 3) != (pDat->PortList[j].Link & 3))
Marc Jonesaee07962008-07-16 21:09:31 +00001260 continue; /* Ensure same source base port */
Marc Jones8ae8c882007-12-19 01:32:08 +00001261
1262 if ((pDat->PortList[i+1].Link & 3) != (pDat->PortList[j+1].Link & 3))
Marc Jonesaee07962008-07-16 21:09:31 +00001263 continue; /* Ensure same destination base port */
Marc Jones8ae8c882007-12-19 01:32:08 +00001264
1265 if ((pDat->PortList[i].Link & 4) != (pDat->PortList[i+1].Link & 4))
Marc Jonesaee07962008-07-16 21:09:31 +00001266 continue; /* Ensure sublink0 routes to sublink0 */
Marc Jones8ae8c882007-12-19 01:32:08 +00001267
Marc Jonesaee07962008-07-16 21:09:31 +00001268 ASSERT((pDat->PortList[j].Link & 4) == (pDat->PortList[j+1].Link & 4)); /* (therefore sublink1 routes to sublink1) */
Marc Jones8ae8c882007-12-19 01:32:08 +00001269
1270 if (pDat->HtBlock->AMD_CB_SkipRegang &&
Marc Jonesaee07962008-07-16 21:09:31 +00001271 pDat->HtBlock->AMD_CB_SkipRegang(pDat->PortList[i].NodeID,
Marc Jones8ae8c882007-12-19 01:32:08 +00001272 pDat->PortList[i].Link & 0x03,
1273 pDat->PortList[i+1].NodeID,
1274 pDat->PortList[i+1].Link & 0x03))
1275 {
Marc Jonesaee07962008-07-16 21:09:31 +00001276 continue; /* Skip regang */
Marc Jones8ae8c882007-12-19 01:32:08 +00001277 }
1278
1279
Marc Jonesaee07962008-07-16 21:09:31 +00001280 pDat->PortList[i].Link &= 0x03; /* Force to point to sublink0 */
Marc Jones8ae8c882007-12-19 01:32:08 +00001281 pDat->PortList[i+1].Link &= 0x03;
Marc Jonesaee07962008-07-16 21:09:31 +00001282 pDat->PortList[i].SelRegang = TRUE; /* Enable link reganging */
Marc Jones8ae8c882007-12-19 01:32:08 +00001283 pDat->PortList[i+1].SelRegang = TRUE;
1284 pDat->PortList[i].PrvWidthOutCap = HT_WIDTH_16_BITS;
1285 pDat->PortList[i+1].PrvWidthOutCap = HT_WIDTH_16_BITS;
1286 pDat->PortList[i].PrvWidthInCap = HT_WIDTH_16_BITS;
1287 pDat->PortList[i+1].PrvWidthInCap = HT_WIDTH_16_BITS;
1288
Marc Jonesaee07962008-07-16 21:09:31 +00001289 /* Delete PortList[j, j+1], slow but easy to debug implementation */
Marc Jones8ae8c882007-12-19 01:32:08 +00001290 pDat->TotalLinks--;
1291 Amdmemcpy(&(pDat->PortList[j]), &(pDat->PortList[j+2]), sizeof(sPortDescriptor)*(pDat->TotalLinks*2-j));
1292 Amdmemset(&(pDat->PortList[pDat->TotalLinks*2]), INVALID_LINK, sizeof(sPortDescriptor)*2);
1293
Marc Jonesaee07962008-07-16 21:09:31 +00001294 /* //High performance, but would make debuging harder due to 'shuffling' of the records */
1295 /* //Amdmemcpy(PortList[TotalPorts-2], PortList[j], SIZEOF(sPortDescriptor)*2); */
1296 /* //TotalPorts -=2; */
Marc Jones8ae8c882007-12-19 01:32:08 +00001297
Marc Jonesaee07962008-07-16 21:09:31 +00001298 break; /* Exit loop, advance to PortList[i+2] */
Marc Jones8ae8c882007-12-19 01:32:08 +00001299 }
1300 }
1301#endif /* HT_BUILD_NC_ONLY */
1302}
1303
1304/*----------------------------------------------------------------------------------------
1305 * void
1306 * selectOptimalWidthAndFrequency(sMainData *pDat)
1307 *
1308 * Description:
1309 * For all links:
1310 * Examine both sides of a link and determine the optimal frequency and width,
1311 * taking into account externally provided limits and enforcing any other limit
1312 * or matching rules as applicable except sublink balancing. Update the port
1313 * list date with the optimal settings.
1314 * Note no hardware state changes in this routine.
1315 *
1316 * Parameters:
1317 * @param[in,out] sMainData* pDat = our global state, port list data
1318 * ---------------------------------------------------------------------------------------
1319 */
1320void selectOptimalWidthAndFrequency(sMainData *pDat)
1321{
1322 u8 i, j;
1323 u32 temp;
1324 u16 cbPCBFreqLimit;
1325 u8 cbPCBABDownstreamWidth;
1326 u8 cbPCBBAUpstreamWidth;
1327
1328 for (i = 0; i < pDat->TotalLinks*2; i += 2)
1329 {
Timothy Pearson55cf7bc2010-03-01 10:30:08 +00001330#if CONFIG_LIMIT_HT_SPEED_200
1331 cbPCBFreqLimit = 0x0001;
1332#elif CONFIG_LIMIT_HT_SPEED_300
1333 cbPCBFreqLimit = 0x0003;
1334#elif CONFIG_LIMIT_HT_SPEED_400
1335 cbPCBFreqLimit = 0x0007;
1336#elif CONFIG_LIMIT_HT_SPEED_500
1337 cbPCBFreqLimit = 0x000F;
1338#elif CONFIG_LIMIT_HT_SPEED_600
1339 cbPCBFreqLimit = 0x001F;
1340#elif CONFIG_LIMIT_HT_SPEED_800
1341 cbPCBFreqLimit = 0x003F;
1342#elif CONFIG_LIMIT_HT_SPEED_1000
1343 cbPCBFreqLimit = 0x007F;
1344#elif CONFIG_LIMIT_HT_SPEED_1200
1345 cbPCBFreqLimit = 0x00FF;
1346#elif CONFIG_LIMIT_HT_SPEED_1400
1347 cbPCBFreqLimit = 0x01FF;
1348#elif CONFIG_LIMIT_HT_SPEED_1600
1349 cbPCBFreqLimit = 0x03FF;
1350#elif CONFIG_LIMIT_HT_SPEED_1800
1351 cbPCBFreqLimit = 0x07FF;
1352#elif CONFIG_LIMIT_HT_SPEED_2000
1353 cbPCBFreqLimit = 0x0FFF;
1354#elif CONFIG_LIMIT_HT_SPEED_2200
1355 cbPCBFreqLimit = 0x1FFF;
1356#elif CONFIG_LIMIT_HT_SPEED_2400
1357 cbPCBFreqLimit = 0x3FFF;
1358#elif CONFIG_LIMIT_HT_SPEED_2600
1359 cbPCBFreqLimit = 0x7FFF;
1360#else
1361 cbPCBFreqLimit = 0xFFFF; // Maximum allowed by autoconfiguration
1362#endif
1363
1364#if CONFIG_LIMIT_HT_DOWN_WIDTH_8
1365 cbPCBABDownstreamWidth = 8;
1366#else
Marc Jones8ae8c882007-12-19 01:32:08 +00001367 cbPCBABDownstreamWidth = 16;
Timothy Pearson55cf7bc2010-03-01 10:30:08 +00001368#endif
1369
1370#if CONFIG_LIMIT_HT_UP_WIDTH_8
1371 cbPCBBAUpstreamWidth = 8;
1372#else
Marc Jones8ae8c882007-12-19 01:32:08 +00001373 cbPCBBAUpstreamWidth = 16;
Timothy Pearson55cf7bc2010-03-01 10:30:08 +00001374#endif
Marc Jones8ae8c882007-12-19 01:32:08 +00001375
1376 if ( (pDat->PortList[i].Type == PORTLIST_TYPE_CPU) && (pDat->PortList[i+1].Type == PORTLIST_TYPE_CPU))
1377 {
1378 if (pDat->HtBlock->AMD_CB_Cpu2CpuPCBLimits)
1379 {
1380 pDat->HtBlock->AMD_CB_Cpu2CpuPCBLimits(
1381 pDat->PortList[i].NodeID,
1382 pDat->PortList[i].Link,
1383 pDat->PortList[i+1].NodeID,
1384 pDat->PortList[i+1].Link,
1385 &cbPCBABDownstreamWidth,
1386 &cbPCBBAUpstreamWidth, &cbPCBFreqLimit
1387 );
1388 }
1389 }
1390 else
1391 {
1392 if (pDat->HtBlock->AMD_CB_IOPCBLimits)
1393 {
1394 pDat->HtBlock->AMD_CB_IOPCBLimits(
1395 pDat->PortList[i+1].NodeID,
1396 pDat->PortList[i+1].HostLink,
1397 pDat->PortList[i+1].HostDepth,
1398 &cbPCBABDownstreamWidth,
1399 &cbPCBBAUpstreamWidth, &cbPCBFreqLimit
1400 );
1401 }
1402 }
1403
1404
1405 temp = pDat->PortList[i].PrvFrequencyCap;
1406 temp &= pDat->PortList[i+1].PrvFrequencyCap;
1407 temp &= cbPCBFreqLimit;
1408 pDat->PortList[i].CompositeFrequencyCap = (u16)temp;
1409 pDat->PortList[i+1].CompositeFrequencyCap = (u16)temp;
1410
1411 ASSERT (temp != 0);
1412 for (j = 15; ; j--)
1413 {
1414 if (temp & ((u32)1 << j))
1415 break;
1416 }
1417
1418 pDat->PortList[i].SelFrequency = j;
1419 pDat->PortList[i+1].SelFrequency = j;
1420
1421 temp = pDat->PortList[i].PrvWidthOutCap;
1422 if (pDat->PortList[i+1].PrvWidthInCap < temp)
1423 temp = pDat->PortList[i+1].PrvWidthInCap;
1424 if (cbPCBABDownstreamWidth < temp)
1425 temp = cbPCBABDownstreamWidth;
1426 pDat->PortList[i].SelWidthOut = (u8)temp;
1427 pDat->PortList[i+1].SelWidthIn = (u8)temp;
1428
1429 temp = pDat->PortList[i].PrvWidthInCap;
1430 if (pDat->PortList[i+1].PrvWidthOutCap < temp)
1431 temp = pDat->PortList[i+1].PrvWidthOutCap;
1432 if (cbPCBBAUpstreamWidth < temp)
1433 temp = cbPCBBAUpstreamWidth;
1434 pDat->PortList[i].SelWidthIn = (u8)temp;
1435 pDat->PortList[i+1].SelWidthOut = (u8)temp;
1436
1437 }
1438}
1439
1440/*----------------------------------------------------------------------------------------
1441 * void
1442 * hammerSublinkFixup(sMainData *pDat)
1443 *
1444 * Description:
1445 * Iterate through all links, checking the frequency of each sublink pair. Make the
1446 * adjustment to the port list data so that the frequencies are at a valid ratio,
1447 * reducing frequency as needed to achieve this. (All links support the minimum 200 MHz
1448 * frequency.) Repeat the above until no adjustments are needed.
1449 * Note no hardware state changes in this routine.
1450 *
1451 * Parameters:
1452 * @param[in,out] sMainData* pDat = our global state, link state and port list
1453 * ---------------------------------------------------------------------------------------
1454 */
1455void hammerSublinkFixup(sMainData *pDat)
1456{
1457#ifndef HT_BUILD_NC_ONLY
1458 u8 i, j, k;
1459 BOOL changes, downgrade;
1460
1461 u8 hiIndex;
1462 u8 hiFreq, loFreq;
1463
1464 u32 temp;
1465
1466 do
1467 {
1468 changes = FALSE;
1469 for (i = 0; i < pDat->TotalLinks*2; i++)
1470 {
Marc Jonesaee07962008-07-16 21:09:31 +00001471 if (pDat->PortList[i].Type != PORTLIST_TYPE_CPU) /* Must be a CPU link */
Marc Jones8ae8c882007-12-19 01:32:08 +00001472 continue;
Marc Jonesaee07962008-07-16 21:09:31 +00001473 if (pDat->PortList[i].Link < 4) /* Only look for for sublink1's */
Marc Jones8ae8c882007-12-19 01:32:08 +00001474 continue;
1475
1476 for (j = 0; j < pDat->TotalLinks*2; j++)
1477 {
Marc Jonesaee07962008-07-16 21:09:31 +00001478 /* Step 1. Find the matching sublink0 */
Marc Jones8ae8c882007-12-19 01:32:08 +00001479 if (pDat->PortList[j].Type != PORTLIST_TYPE_CPU)
1480 continue;
1481 if (pDat->PortList[j].NodeID != pDat->PortList[i].NodeID)
1482 continue;
1483 if (pDat->PortList[j].Link != (pDat->PortList[i].Link & 0x03))
1484 continue;
1485
Marc Jonesaee07962008-07-16 21:09:31 +00001486 /* Step 2. Check for an illegal frequency ratio */
Marc Jones8ae8c882007-12-19 01:32:08 +00001487 if (pDat->PortList[i].SelFrequency >= pDat->PortList[j].SelFrequency)
1488 {
1489 hiIndex = i;
1490 hiFreq = pDat->PortList[i].SelFrequency;
1491 loFreq = pDat->PortList[j].SelFrequency;
1492 }
1493 else
1494 {
1495 hiIndex = j;
1496 hiFreq = pDat->PortList[j].SelFrequency;
1497 loFreq = pDat->PortList[i].SelFrequency;
1498 }
1499
1500 if (hiFreq == loFreq)
Marc Jonesaee07962008-07-16 21:09:31 +00001501 break; /* The frequencies are 1:1, no need to do anything */
Marc Jones8ae8c882007-12-19 01:32:08 +00001502
1503 downgrade = FALSE;
1504
1505 if (hiFreq == 13)
1506 {
Marc Jonesaee07962008-07-16 21:09:31 +00001507 if ((loFreq != 7) && /* {13, 7} 2400MHz / 1200MHz 2:1 */
1508 (loFreq != 4) && /* {13, 4} 2400MHz / 600MHz 4:1 */
1509 (loFreq != 2) ) /* {13, 2} 2400MHz / 400MHz 6:1 */
Marc Jones8ae8c882007-12-19 01:32:08 +00001510 downgrade = TRUE;
1511 }
1512 else if (hiFreq == 11)
1513 {
Marc Jonesaee07962008-07-16 21:09:31 +00001514 if ((loFreq != 6)) /* {11, 6} 2000MHz / 1000MHz 2:1 */
Marc Jones8ae8c882007-12-19 01:32:08 +00001515 downgrade = TRUE;
1516 }
1517 else if (hiFreq == 9)
1518 {
Marc Jonesaee07962008-07-16 21:09:31 +00001519 if ((loFreq != 5) && /* { 9, 5} 1600MHz / 800MHz 2:1 */
1520 (loFreq != 2) && /* { 9, 2} 1600MHz / 400MHz 4:1 */
1521 (loFreq != 0) ) /* { 9, 0} 1600MHz / 200Mhz 8:1 */
Marc Jones8ae8c882007-12-19 01:32:08 +00001522 downgrade = TRUE;
1523 }
1524 else if (hiFreq == 7)
1525 {
Marc Jonesaee07962008-07-16 21:09:31 +00001526 if ((loFreq != 4) && /* { 7, 4} 1200MHz / 600MHz 2:1 */
1527 (loFreq != 0) ) /* { 7, 0} 1200MHz / 200MHz 6:1 */
Marc Jones8ae8c882007-12-19 01:32:08 +00001528 downgrade = TRUE;
1529 }
1530 else if (hiFreq == 5)
1531 {
Marc Jonesaee07962008-07-16 21:09:31 +00001532 if ((loFreq != 2) && /* { 5, 2} 800MHz / 400MHz 2:1 */
1533 (loFreq != 0) ) /* { 5, 0} 800MHz / 200MHz 4:1 */
Marc Jones8ae8c882007-12-19 01:32:08 +00001534 downgrade = TRUE;
1535 }
1536 else if (hiFreq == 2)
1537 {
Marc Jonesaee07962008-07-16 21:09:31 +00001538 if ((loFreq != 0)) /* { 2, 0} 400MHz / 200MHz 2:1 */
Marc Jones8ae8c882007-12-19 01:32:08 +00001539 downgrade = TRUE;
1540 }
1541 else
1542 {
Marc Jonesaee07962008-07-16 21:09:31 +00001543 downgrade = TRUE; /* no legal ratios for hiFreq */
Marc Jones8ae8c882007-12-19 01:32:08 +00001544 }
1545
Marc Jonesaee07962008-07-16 21:09:31 +00001546 /* Step 3. Downgrade the higher of the two frequencies, and set nochanges to FALSE */
Marc Jones8ae8c882007-12-19 01:32:08 +00001547 if (downgrade)
1548 {
Marc Jonesaee07962008-07-16 21:09:31 +00001549 /* Although the problem was with the port specified by hiIndex, we need to */
1550 /* downgrade both ends of the link. */
1551 hiIndex = hiIndex & 0xFE; /* Select the 'upstream' (i.e. even) port */
Marc Jones8ae8c882007-12-19 01:32:08 +00001552
1553 temp = pDat->PortList[hiIndex].CompositeFrequencyCap;
1554
Marc Jonesaee07962008-07-16 21:09:31 +00001555 /* Remove hiFreq from the list of valid frequencies */
1556 temp = temp & ~((uint32)1 << hiFreq);
Marc Jones8ae8c882007-12-19 01:32:08 +00001557 ASSERT (temp != 0);
Marc Jonesaee07962008-07-16 21:09:31 +00001558 pDat->PortList[hiIndex].CompositeFrequencyCap = (uint16)temp;
1559 pDat->PortList[hiIndex+1].CompositeFrequencyCap = (uint16)temp;
Marc Jones8ae8c882007-12-19 01:32:08 +00001560
1561 for (k = 15; ; k--)
1562 {
1563 if (temp & ((u32)1 << k))
1564 break;
1565 }
1566
1567 pDat->PortList[hiIndex].SelFrequency = k;
1568 pDat->PortList[hiIndex+1].SelFrequency = k;
1569
1570 changes = TRUE;
1571 }
1572 }
1573 }
Marc Jonesaee07962008-07-16 21:09:31 +00001574 } while (changes); /* Repeat until a valid configuration is reached */
Marc Jones8ae8c882007-12-19 01:32:08 +00001575#endif /* HT_BUILD_NC_ONLY */
1576}
1577
1578/*----------------------------------------------------------------------------------------
1579 * void
1580 * linkOptimization(sMainData *pDat)
1581 *
1582 * Description:
1583 * Based on link capabilities, apply optimization rules to come up with the real best
1584 * settings, including several external limit decision from call backs. This includes
1585 * handling of sublinks. Finally, after the port list data is updated, set the hardware
1586 * state for all links.
1587 *
1588 * Parameters:
1589 * @param[in] sMainData* pDat = our global state
1590 * ---------------------------------------------------------------------------------------
1591 */
1592void linkOptimization(sMainData *pDat)
1593{
1594 pDat->nb->gatherLinkData(pDat, pDat->nb);
1595 regangLinks(pDat);
1596 selectOptimalWidthAndFrequency(pDat);
1597 hammerSublinkFixup(pDat);
1598 pDat->nb->setLinkData(pDat, pDat->nb);
1599}
1600
1601
1602/*----------------------------------------------------------------------------------------
1603 * void
1604 * trafficDistribution(sMainData *pDat)
1605 *
1606 * Description:
1607 * In the case of a two node system with both sublinks used, enable the traffic
1608 * distribution feature.
1609 *
1610 * Parameters:
1611 * @param[in] sMainData* pDat = our global state, port list data
1612 * ---------------------------------------------------------------------------------------
1613 */
1614void trafficDistribution(sMainData *pDat)
1615{
1616#ifndef HT_BUILD_NC_ONLY
1617 u32 links01, links10;
1618 u8 linkCount;
1619 u8 i;
1620
Marc Jonesaee07962008-07-16 21:09:31 +00001621 /* Traffic Distribution is only used when there are exactly two nodes in the system */
Marc Jones8ae8c882007-12-19 01:32:08 +00001622 if (pDat->NodesDiscovered+1 != 2)
1623 return;
1624
1625 links01 = 0;
1626 links10 = 0;
1627 linkCount = 0;
1628 for (i = 0; i < pDat->TotalLinks*2; i += 2)
1629 {
1630 if ((pDat->PortList[i].Type == PORTLIST_TYPE_CPU) && (pDat->PortList[i+1].Type == PORTLIST_TYPE_CPU))
1631 {
1632 links01 |= (u32)1 << pDat->PortList[i].Link;
1633 links10 |= (u32)1 << pDat->PortList[i+1].Link;
1634 linkCount++;
1635 }
1636 }
1637 ASSERT(linkCount != 0);
1638 if (linkCount == 1)
Marc Jonesaee07962008-07-16 21:09:31 +00001639 return; /* Don't setup Traffic Distribution if only one link is being used */
Marc Jones8ae8c882007-12-19 01:32:08 +00001640
1641 pDat->nb->writeTrafficDistribution(links01, links10, pDat->nb);
1642#endif /* HT_BUILD_NC_ONLY */
1643}
1644
1645/*----------------------------------------------------------------------------------------
1646 * void
1647 * tuning(sMainData *pDat)
1648 *
1649 * Description:
1650 * Handle system and performance tunings, such as traffic distribution, fifo and
1651 * buffer tuning, and special config tunings.
1652 *
1653 * Parameters:
1654 * @param[in] sMainData* pDat = our global state, port list data
1655 * ---------------------------------------------------------------------------------------
1656 */
1657void tuning(sMainData *pDat)
1658{
1659 u8 i;
1660
1661 /* See if traffic distribution can be done and do it if so
1662 * or allow system specific customization
1663 */
1664 if ((pDat->HtBlock->AMD_CB_CustomizeTrafficDistribution == NULL)
1665 || !pDat->HtBlock->AMD_CB_CustomizeTrafficDistribution())
1666 {
1667 trafficDistribution(pDat);
1668 }
1669
1670 /* For each node, invoke northbridge specific buffer tunings or
1671 * system specific customizations.
1672 */
1673 for (i=0; i < pDat->NodesDiscovered + 1; i++)
1674 {
1675 if ((pDat->HtBlock->AMD_CB_CustomizeBuffers == NULL)
1676 || !pDat->HtBlock->AMD_CB_CustomizeBuffers(i))
1677 {
1678 pDat->nb->bufferOptimizations(i, pDat, pDat->nb);
1679 }
1680 }
1681}
1682
1683/*----------------------------------------------------------------------------------------
1684 * BOOL
1685 * isSanityCheckOk()
1686 *
1687 * Description:
1688 * Perform any general sanity checks which should prevent HT from running if they fail.
1689 * Currently only the "Must run on BSP only" check.
1690 *
1691 * Parameters:
1692 * @param[out] result BOOL = true if check is ok, false if it failed
1693 * ---------------------------------------------------------------------------------------
1694 */
1695BOOL isSanityCheckOk()
1696{
1697 uint64 qValue;
1698
1699 AmdMSRRead(APIC_Base, &qValue);
1700
1701 return ((qValue.lo & ((u32)1 << APIC_Base_BSP)) != 0);
1702}
1703
1704/***************************************************************************
1705 *** HT Initialize ***
1706 ***************************************************************************/
1707
1708/*----------------------------------------------------------------------------------------
1709 * void
1710 * htInitialize(AMD_HTBLOCK *pBlock)
1711 *
1712 * Description:
1713 * This is the top level external interface for Hypertransport Initialization.
1714 * Create our initial internal state, initialize the coherent fabric,
1715 * initialize the non-coherent chains, and perform any required fabric tuning or
1716 * optimization.
1717 *
1718 * Parameters:
1719 * @param[in] AMD_HTBLOCK* pBlock = Our Initial State including possible
1720 * topologies and routings, non coherent bus
1721 * assignment info, and actual
1722 * wrapper or OEM call back routines.
1723 * ---------------------------------------------------------------------------------------
1724 */
1725void amdHtInitialize(AMD_HTBLOCK *pBlock)
1726{
1727 sMainData pDat;
1728 cNorthBridge nb;
1729
1730 if (isSanityCheckOk())
1731 {
1732 newNorthBridge(0, &nb);
1733
1734 pDat.HtBlock = pBlock;
1735 pDat.nb = &nb;
1736 pDat.sysMpCap = nb.maxNodes;
1737 nb.isCapable(0, &pDat, pDat.nb);
1738 coherentInit(&pDat);
1739
1740 pDat.AutoBusCurrent = pBlock->AutoBusStart;
1741 pDat.UsedCfgMapEntires = 0;
1742 ncInit(&pDat);
1743 linkOptimization(&pDat);
1744 tuning(&pDat);
1745 }
1746}