Uniformly spell frequency unit symbol as Hz
[coreboot.git] / src / northbridge / amd / amdht / h3finit.c
blob764d2988b422cce8dc674dce71a36ec055095d51
1 /*
2 * This file is part of the coreboot project.
4 * Copyright (C) 2007 Advanced Micro Devices, Inc.
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.
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.
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
21 *----------------------------------------------------------------------------
22 * MODULES USED
24 *----------------------------------------------------------------------------
27 #undef FILECODE
28 #define FILECODE 0xF001
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"
41 /*----------------------------------------------------------------------------
42 * DEFINITIONS AND MACROS
44 *----------------------------------------------------------------------------
47 #undef FILECODE
48 #define FILECODE 0xF001
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
54 /*----------------------------------------------------------------------------
55 * TYPEDEFS AND STRUCTURES
57 *----------------------------------------------------------------------------
60 /*----------------------------------------------------------------------------
61 * PROTOTYPES OF LOCAL FUNCTIONS
63 *----------------------------------------------------------------------------
66 /*----------------------------------------------------------------------------
67 * EXPORTED FUNCTIONS
69 *----------------------------------------------------------------------------
72 /*----------------------------------------------------------------------------
73 * LOCAL FUNCTIONS
75 *----------------------------------------------------------------------------
77 #ifndef HT_BUILD_NC_ONLY
79 **************************************************************************
80 * Routing table decompressor
81 **************************************************************************
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.
98 * pseudo definition of compressed graph:
99 * typedef struct
101 * BIT broadcast[8];
102 * uint4 responseRoute;
103 * uint4 requestRoute;
104 * } sRoute;
105 * typedef struct
107 * u8 size;
108 * sRoute graph[size][size];
109 * } sGraph;
111 **************************************************************************
114 /*----------------------------------------------------------------------------------------
115 * u8
116 * graphHowManyNodes(u8 *graph)
118 * Description:
119 * Returns the number of nodes in the compressed graph
121 * Parameters:
122 * @param[in] u8 graph = a compressed graph
123 * @param[out] u8 results = the number of nodes in the graph
124 * ---------------------------------------------------------------------------------------
126 static u8 graphHowManyNodes(u8 *graph)
128 return graph[0];
131 /*----------------------------------------------------------------------------------------
132 * BOOL
133 * graphIsAdjacent(u8 *graph, u8 nodeA, u8 nodeB)
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.
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 * ---------------------------------------------------------------------------------------
147 static BOOL graphIsAdjacent(u8 *graph, u8 nodeA, u8 nodeB)
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;
155 /*----------------------------------------------------------------------------------------
156 * u8
157 * graphGetRsp(u8 *graph, u8 nodeA, u8 nodeB)
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.
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 * ---------------------------------------------------------------------------------------
173 static u8 graphGetRsp(u8 *graph, u8 nodeA, u8 nodeB)
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;
181 /*----------------------------------------------------------------------------------------
182 * u8
183 * graphGetReq(u8 *graph, u8 nodeA, u8 nodeB)
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.
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 * ---------------------------------------------------------------------------------------
199 static u8 graphGetReq(u8 *graph, u8 nodeA, u8 nodeB)
201 u8 size = graph[0];
202 ASSERT(size <= MAX_NODES);
203 ASSERT((nodeA < size) && (nodeB < size));
204 return (graph[1+(nodeA*size+nodeB)*2+1] & 0x0F);
207 /*----------------------------------------------------------------------------------------
208 * u8
209 * graphGetBc(u8 *graph, u8 nodeA, u8 nodeB)
211 * Description:
212 * Returns a bit vector of nodes that nodeA should forward a broadcast from
213 * nodeB towards
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 * ---------------------------------------------------------------------------------------
222 static u8 graphGetBc(u8 *graph, u8 nodeA, u8 nodeB)
224 u8 size = graph[0];
225 ASSERT(size <= MAX_NODES);
226 ASSERT((nodeA < size) && (nodeB < size));
227 return graph[1+(nodeA*size+nodeB)*2];
231 /***************************************************************************
232 *** GENERIC HYPERTRANSPORT DISCOVERY CODE ***
233 ***************************************************************************/
235 /*----------------------------------------------------------------------------------------
236 * void
237 * routeFromBSP(u8 targetNode, u8 actualTarget, sMainData *pDat)
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.
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 * ---------------------------------------------------------------------------------------
251 static void routeFromBSP(u8 targetNode, u8 actualTarget, sMainData *pDat)
253 u8 predecessorNode, predecessorLink, currentPair;
255 if (targetNode == 0)
256 return; /* BSP has no predecessor, stop */
258 /* Search for the link that connects targetNode to its predecessor */
259 currentPair = 0;
260 while (pDat->PortList[currentPair*2+1].NodeID != targetNode)
262 currentPair++;
263 ASSERT(currentPair < pDat->TotalLinks);
266 predecessorNode = pDat->PortList[currentPair*2].NodeID;
267 predecessorLink = pDat->PortList[currentPair*2].Link;
269 /* Recursively call self to ensure the route from the BSP to the Predecessor */
270 /* Node is established */
271 routeFromBSP(predecessorNode, actualTarget, pDat);
273 pDat->nb->writeRoutingTable(predecessorNode, actualTarget, predecessorLink, pDat->nb);
276 /*----------------------------------------------------------------------------------------
277 * u8
278 * convertNodeToLink(u8 srcNode, u8 targetNode, sMainData *pDat)
280 * Description:
281 * Return the link on source node which connects to target node
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 * ---------------------------------------------------------------------------------------
290 static u8 convertNodeToLink(u8 srcNode, u8 targetNode, sMainData *pDat)
292 u8 targetlink = INVALID_LINK;
293 u8 k;
295 for (k = 0; k < pDat->TotalLinks*2; k += 2)
297 if ((pDat->PortList[k+0].NodeID == srcNode) && (pDat->PortList[k+1].NodeID == targetNode))
299 targetlink = pDat->PortList[k+0].Link;
300 break;
302 else if ((pDat->PortList[k+1].NodeID == srcNode) && (pDat->PortList[k+0].NodeID == targetNode))
304 targetlink = pDat->PortList[k+1].Link;
305 break;
308 ASSERT(targetlink != INVALID_LINK);
310 return targetlink;
314 /*----------------------------------------------------------------------------------------
315 * void
316 * htDiscoveryFloodFill(sMainData *pDat)
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).
325 * Parameters:
326 * @param[in] sMainData* pDat = our global state
327 * ---------------------------------------------------------------------------------------
329 static void htDiscoveryFloodFill(sMainData *pDat)
331 u8 currentNode = 0;
332 u8 currentLink;
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
338 while (currentNode <= pDat->NodesDiscovered)
340 u32 temp;
342 if (currentNode != 0)
344 /* Set path from BSP to currentNode */
345 routeFromBSP(currentNode, currentNode, pDat);
347 /* Set path from BSP to currentNode for currentNode+1 if
348 * currentNode+1 != MAX_NODES
350 if (currentNode+1 != MAX_NODES)
351 routeFromBSP(currentNode, currentNode+1, pDat);
353 /* Configure currentNode to route traffic to the BSP through its
354 * default link
356 pDat->nb->writeRoutingTable(currentNode, 0, pDat->nb->readDefLnk(currentNode, pDat->nb), pDat->nb);
359 /* Set currentNode's NodeID field to currentNode */
360 pDat->nb->writeNodeID(currentNode, currentNode, pDat->nb);
362 /* Enable routing tables on currentNode*/
363 pDat->nb->enableRoutingTables(currentNode, pDat->nb);
365 for (currentLink = 0; currentLink < pDat->nb->maxLinks; currentLink++)
367 BOOL linkfound;
368 u8 token;
370 if (pDat->HtBlock->AMD_CB_IgnoreLink && pDat->HtBlock->AMD_CB_IgnoreLink(currentNode, currentLink))
371 continue;
373 if (pDat->nb->readTrueLinkFailStatus(currentNode, currentLink, pDat, pDat->nb))
374 continue;
376 /* Make sure that the link is connected, coherent, and ready */
377 if (!pDat->nb->verifyLinkIsCoherent(currentNode, currentLink, pDat->nb))
378 continue;
381 /* Test to see if the currentLink has already been explored */
382 linkfound = FALSE;
383 for (temp = 0; temp < pDat->TotalLinks; temp++)
385 if ((pDat->PortList[temp*2+1].NodeID == currentNode) &&
386 (pDat->PortList[temp*2+1].Link == currentLink))
388 linkfound = TRUE;
389 break;
392 if (linkfound)
394 /* We had already expored this link */
395 continue;
398 if (pDat->nb->handleSpecialLinkCase(currentNode, currentLink, pDat, pDat->nb))
400 continue;
403 /* Modify currentNode's routing table to use currentLink to send
404 * traffic to currentNode+1
406 pDat->nb->writeRoutingTable(currentNode, currentNode+1, currentLink, pDat->nb);
408 /* Check the northbridge of the node we just found, to make sure it is compatible
409 * before doing anything else to it.
411 if (!pDat->nb->isCompatible(currentNode+1, pDat->nb))
413 u8 nodeToKill;
415 /* Notify BIOS of event (while variables are still the same) */
416 if (pDat->HtBlock->AMD_CB_EventNotify)
418 sHtEventCohFamilyFeud evt;
419 evt.eSize = sizeof(sHtEventCohFamilyFeud);
420 evt.node = currentNode;
421 evt.link = currentLink;
422 evt.totalNodes = pDat->NodesDiscovered;
424 pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_ERROR,
425 HT_EVENT_COH_FAMILY_FEUD,
426 (u8 *)&evt);
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.
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.
442 for (currentLink = 0; currentLink < pDat->nb->maxLinks; currentLink++)
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);
449 for (nodeToKill = 0; nodeToKill < pDat->nb->maxNodes; nodeToKill++)
451 pDat->nb->writeFullRoutingTable(0, nodeToKill, ROUTETOSELF, ROUTETOSELF, 0, pDat->nb);
454 /* End Coherent Discovery */
455 STOP_HERE;
456 break;
459 /* Read token from Current+1 */
460 token = pDat->nb->readToken(currentNode+1, pDat->nb);
461 ASSERT(token <= pDat->NodesDiscovered);
462 if (token == 0)
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))
469 u8 nodeToKill;
471 /* Notify BIOS of event */
472 if (pDat->HtBlock->AMD_CB_EventNotify)
474 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;
481 pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_ERROR,
482 HT_EVENT_COH_MPCAP_MISMATCH,
483 (u8 *)&evt);
486 pDat->NodesDiscovered = 0;
487 currentNode = 0;
488 pDat->TotalLinks = 0;
490 for (nodeToKill = 0; nodeToKill < pDat->nb->maxNodes; nodeToKill++)
492 pDat->nb->writeFullRoutingTable(0, nodeToKill, ROUTETOSELF, ROUTETOSELF, 0, pDat->nb);
495 /* End Coherent Discovery */
496 STOP_HERE;
497 break;
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.
505 if (pDat->HtBlock->AMD_CB_EventNotify)
507 sHtEventCohNodeDiscovered evt;
508 evt.eSize = sizeof(sHtEventCohNodeDiscovered);
509 evt.node = currentNode;
510 evt.link = currentLink;
511 evt.newNode = token;
513 pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_INFO,
514 HT_EVENT_COH_NODE_DISCOVERED,
515 (u8 *)&evt);
519 if (pDat->TotalLinks == MAX_PLATFORM_LINKS)
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.
531 if (pDat->HtBlock->AMD_CB_EventNotify)
533 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;
541 pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_ERROR,
542 HT_EVENT_COH_LINK_EXCEED,
543 (u8 *)&evt);
545 /* Force link and node loops to halt */
546 STOP_HERE;
547 currentNode = pDat->NodesDiscovered;
548 break;
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;
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;
559 pDat->TotalLinks++;
561 if ( !pDat->sysMatrix[currentNode][token] )
563 pDat->sysDegree[currentNode]++;
564 pDat->sysDegree[token]++;
565 pDat->sysMatrix[currentNode][token] = TRUE;
566 pDat->sysMatrix[token][currentNode] = TRUE;
569 currentNode++;
574 /***************************************************************************
575 *** ISOMORPHISM BASED ROUTING TABLE GENERATION CODE ***
576 ***************************************************************************/
578 /*----------------------------------------------------------------------------------------
579 * BOOL
580 * isoMorph(u8 i, sMainData *pDat)
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).
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 * ---------------------------------------------------------------------------------------
598 static BOOL isoMorph(u8 i, sMainData *pDat)
600 u8 j, k;
601 u8 nodecnt;
603 /* We have only been called if nodecnt == pSelected->size ! */
604 nodecnt = pDat->NodesDiscovered+1;
606 if (i != nodecnt)
608 /* Keep building the permutation */
609 for (j = 0; j < nodecnt; j++)
611 /* Make sure the degree matches */
612 if (pDat->sysDegree[i] != pDat->dbDegree[j])
613 continue;
615 /* Make sure that j hasn't been used yet (ought to use a "used" */
616 /* array instead, might be faster) */
617 for (k = 0; k < i; k++)
619 if (pDat->Perm[k] == j)
620 break;
622 if (k != i)
623 continue;
624 pDat->Perm[i] = j;
625 if (isoMorph(i+1, pDat))
626 return TRUE;
628 return FALSE;
629 } else {
630 /* Test to see if the permutation is isomorphic */
631 for (j = 0; j < nodecnt; j++)
633 for (k = 0; k < nodecnt; k++)
635 if ( pDat->sysMatrix[j][k] !=
636 pDat->dbMatrix[pDat->Perm[j]][pDat->Perm[k]] )
637 return FALSE;
640 return TRUE;
645 /*----------------------------------------------------------------------------------------
646 * void
647 * lookupComputeAndLoadRoutingTables(sMainData *pDat)
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.
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.
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.
667 * Parameters:
668 * @param[in] sMainData* pDat = our global state, the discovered fabric,
669 * @param[out] degree matrix, permutation
670 * ---------------------------------------------------------------------------------------
672 static void lookupComputeAndLoadRoutingTables(sMainData *pDat)
674 u8 **pTopologyList;
675 u8 *pSelected;
677 int i, j, k, size;
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)
684 getAmdTopolist(&pTopologyList);
687 pSelected = *pTopologyList;
688 while (pSelected != NULL)
690 if (graphHowManyNodes(pSelected) == size)
692 /* Build Degree vector and Adjency Matrix for this entry */
693 for (i = 0; i < size; i++)
695 pDat->dbDegree[i] = 0;
696 for (j = 0; j < size; j++)
698 if (graphIsAdjacent(pSelected, i, j))
700 pDat->dbMatrix[i][j] = 1;
701 pDat->dbDegree[i]++;
703 else
705 pDat->dbMatrix[i][j] = 0;
709 if (isoMorph(0, pDat))
710 break; /* A matching topology was found */
713 pTopologyList++;
714 pSelected = *pTopologyList;
717 if (pSelected != NULL)
719 /* Compute the reverse Permutation */
720 for (i = 0; i < size; i++)
722 pDat->ReversePerm[pDat->Perm[i]] = i;
725 /* Start with the last discovered node, and move towards the BSP */
726 for (i = size-1; i >= 0; i--)
728 for (j = 0; j < size; j++)
730 u8 ReqTargetLink, RspTargetLink;
731 u8 ReqTargetNode, RspTargetNode;
733 u8 AbstractBcTargetNodes = graphGetBc(pSelected, pDat->Perm[i], pDat->Perm[j]);
734 u32 BcTargetLinks = 0;
736 for (k = 0; k < MAX_NODES; k++)
738 if (AbstractBcTargetNodes & ((u32)1<<k))
740 BcTargetLinks |= (u32)1 << convertNodeToLink(i, pDat->ReversePerm[k], pDat);
744 if (i == j)
746 ReqTargetLink = ROUTETOSELF;
747 RspTargetLink = ROUTETOSELF;
749 else
751 ReqTargetNode = graphGetReq(pSelected, pDat->Perm[i], pDat->Perm[j]);
752 ReqTargetLink = convertNodeToLink(i, pDat->ReversePerm[ReqTargetNode], pDat);
754 RspTargetNode = graphGetRsp(pSelected, pDat->Perm[i], pDat->Perm[j]);
755 RspTargetLink = convertNodeToLink(i, pDat->ReversePerm[RspTargetNode], pDat);
758 pDat->nb->writeFullRoutingTable(i, j, ReqTargetLink, RspTargetLink, BcTargetLinks, pDat->nb);
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.
765 if (size < pDat->nb->maxNodes)
767 pDat->nb->writeFullRoutingTable(i, size, ROUTETOSELF, ROUTETOSELF, 0, pDat->nb);
772 else
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.
781 if (pDat->HtBlock->AMD_CB_EventNotify)
783 sHtEventCohNoTopology evt;
784 evt.eSize = sizeof(sHtEventCohNoTopology);
785 evt.totalNodes = pDat->NodesDiscovered;
787 pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_ERROR,
788 HT_EVENT_COH_NO_TOPOLOGY,
789 (u8 *)&evt);
791 STOP_HERE;
792 /* Force 1P */
793 pDat->NodesDiscovered = 0;
794 pDat->TotalLinks = 0;
795 pDat->nb->enableRoutingTables(0, pDat->nb);
798 #endif /* HT_BUILD_NC_ONLY */
801 /*----------------------------------------------------------------------------------------
802 * void
803 * finializeCoherentInit(sMainData *pDat)
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.
809 * Parameters:
810 * @param[in] sMainData* pDat = our global state, number of nodes discovered.
811 * ---------------------------------------------------------------------------------------
813 static void finializeCoherentInit(sMainData *pDat)
815 u8 curNode;
817 u8 totalCores = 0;
818 for (curNode = 0; curNode < pDat->NodesDiscovered+1; curNode++)
820 totalCores += pDat->nb->getNumCoresOnNode(curNode, pDat->nb);
823 for (curNode = 0; curNode < pDat->NodesDiscovered+1; curNode++)
825 pDat->nb->setTotalNodesAndCores(curNode, pDat->NodesDiscovered+1, totalCores, pDat->nb);
828 for (curNode = 0; curNode < pDat->NodesDiscovered+1; curNode++)
830 pDat->nb->limitNodes(curNode, pDat->nb);
835 /*----------------------------------------------------------------------------------------
836 * void
837 * coherentInit(sMainData *pDat)
839 * Description:
840 * Perform discovery and initialization of the coherent fabric.
842 * Parameters:
843 * @param[in] sMainData* pDat = our global state
844 * ---------------------------------------------------------------------------------------
846 static void coherentInit(sMainData *pDat)
848 #ifdef HT_BUILD_NC_ONLY
849 /* Replace discovery process with:
850 * No other nodes, no coherent links
851 * Enable routing tables on currentNode, for power on self route
853 pDat->NodesDiscovered = 0;
854 pDat->TotalLinks = 0;
855 pDat->nb->enableRoutingTables(0, pDat->nb);
856 #else
857 u8 i, j;
859 pDat->NodesDiscovered = 0;
860 pDat->TotalLinks = 0;
861 for (i = 0; i < MAX_NODES; i++)
863 pDat->sysDegree[i] = 0;
864 for (j = 0; j < MAX_NODES; j++)
866 pDat->sysMatrix[i][j] = 0;
870 htDiscoveryFloodFill(pDat);
871 lookupComputeAndLoadRoutingTables(pDat);
872 #endif
873 finializeCoherentInit(pDat);
876 /***************************************************************************
877 *** Non-coherent init code ***
878 *** Algorithms ***
879 ***************************************************************************/
880 /*----------------------------------------------------------------------------------------
881 * void
882 * processLink(u8 node, u8 link, sMainData *pDat)
884 * Description:
885 * Process a non-coherent link, enabling a range of bus numbers, and setting the device
886 * ID for all devices found
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 * ---------------------------------------------------------------------------------------
894 static void processLink(u8 node, u8 link, sMainData *pDat)
896 u8 secBus, subBus;
897 u32 currentBUID;
898 u32 temp;
899 u32 unitIDcnt;
900 SBDFO currentPtr;
901 u8 depth;
902 const u8 *pSwapPtr;
904 SBDFO lastSBDFO = ILLEGAL_SBDFO;
905 u8 lastLink = 0;
907 ASSERT(node < pDat->nb->maxNodes && link < pDat->nb->maxLinks);
909 if ((pDat->HtBlock->AMD_CB_OverrideBusNumbers == NULL)
910 || !pDat->HtBlock->AMD_CB_OverrideBusNumbers(node, link, &secBus, &subBus))
912 /* Assign Bus numbers */
913 if (pDat->AutoBusCurrent >= pDat->HtBlock->AutoBusMax)
915 /* If we run out of Bus Numbers notify, if call back unimplemented or if it
916 * returns, skip this chain
918 if (pDat->HtBlock->AMD_CB_EventNotify)
920 sHTEventNcohBusMaxExceed evt;
921 evt.eSize = sizeof(sHTEventNcohBusMaxExceed);
922 evt.node = node;
923 evt.link = link;
924 evt.bus = pDat->AutoBusCurrent;
926 pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_ERROR,HT_EVENT_NCOH_BUS_MAX_EXCEED,(u8 *)&evt);
928 STOP_HERE;
929 return;
932 if (pDat->UsedCfgMapEntires >= 4)
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.
937 if (pDat->HtBlock->AMD_CB_EventNotify)
939 sHtEventNcohCfgMapExceed evt;
940 evt.eSize = sizeof(sHtEventNcohCfgMapExceed);
941 evt.node = node;
942 evt.link = link;
944 pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_ERROR,
945 HT_EVENT_NCOH_CFG_MAP_EXCEED,
946 (u8 *)&evt);
948 STOP_HERE;
949 return;
952 secBus = pDat->AutoBusCurrent;
953 subBus = secBus + pDat->HtBlock->AutoBusIncrement-1;
954 pDat->AutoBusCurrent += pDat->HtBlock->AutoBusIncrement;
957 pDat->nb->setCFGAddrMap(pDat->UsedCfgMapEntires, secBus, subBus, node, link, pDat, pDat->nb);
958 pDat->UsedCfgMapEntires++;
960 if ((pDat->HtBlock->AMD_CB_ManualBUIDSwapList != NULL)
961 && pDat->HtBlock->AMD_CB_ManualBUIDSwapList(node, link, &pSwapPtr))
963 /* Manual non-coherent BUID assignment */
965 /* Assign BUID's per manual override */
966 while (*pSwapPtr != 0xFF)
968 currentPtr = MAKE_SBDFO(0, secBus, *pSwapPtr, 0, 0);
969 pSwapPtr++;
973 AmdPCIFindNextCap(&currentPtr);
974 ASSERT(currentPtr != ILLEGAL_SBDFO);
975 AmdPCIRead(currentPtr, &temp);
976 } while (!IS_HT_SLAVE_CAPABILITY(temp));
978 currentBUID = *pSwapPtr;
979 pSwapPtr++;
980 AmdPCIWriteBits(currentPtr, 20, 16, &currentBUID);
983 /* Build chain of devices */
984 depth = 0;
985 pSwapPtr++;
986 while (*pSwapPtr != 0xFF)
988 pDat->PortList[pDat->TotalLinks*2].NodeID = node;
989 if (depth == 0)
991 pDat->PortList[pDat->TotalLinks*2].Type = PORTLIST_TYPE_CPU;
992 pDat->PortList[pDat->TotalLinks*2].Link = link;
994 else
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;
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;
1008 currentPtr = MAKE_SBDFO(0, secBus, (*pSwapPtr & 0x3F), 0, 0);
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;
1018 /* Bit 6 indicates whether orientation override is desired.
1019 * Bit 7 indicates the upstream link if overriding.
1021 /* assert catches at least the one known incorrect setting */
1022 ASSERT ((*pSwapPtr & 0x40) || (!(*pSwapPtr & 0x80)));
1023 if (*pSwapPtr & 0x40)
1025 /* Override the device's orientation */
1026 lastLink = *pSwapPtr >> 7;
1028 else
1030 /* Detect the device's orientation */
1031 AmdPCIReadBits(currentPtr, 26, 26, &temp);
1032 lastLink = (u8)temp;
1034 pDat->PortList[pDat->TotalLinks*2+1].Link = lastLink;
1036 depth++;
1037 pDat->TotalLinks++;
1038 pSwapPtr++;
1041 else
1043 /* Automatic non-coherent device detection */
1044 depth = 0;
1045 currentBUID = 1;
1046 while (1)
1048 currentPtr = MAKE_SBDFO(0, secBus, 0, 0, 0);
1050 AmdPCIRead(currentPtr, &temp);
1051 if (temp == 0xFFFFFFFF)
1052 /* No device found at currentPtr */
1053 break;
1055 if (pDat->TotalLinks == MAX_PLATFORM_LINKS)
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.
1062 if (pDat->HtBlock->AMD_CB_EventNotify)
1064 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;
1071 pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_ERROR,
1072 HT_EVENT_NCOH_LINK_EXCEED,
1073 (u8 *)&evt);
1075 /* Force link loop to halt */
1076 STOP_HERE;
1077 break;
1080 pDat->PortList[pDat->TotalLinks*2].NodeID = node;
1081 if (depth == 0)
1083 pDat->PortList[pDat->TotalLinks*2].Type = PORTLIST_TYPE_CPU;
1084 pDat->PortList[pDat->TotalLinks*2].Link = link;
1086 else
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;
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;
1102 AmdPCIFindNextCap(&currentPtr);
1103 ASSERT(currentPtr != ILLEGAL_SBDFO);
1104 AmdPCIRead(currentPtr, &temp);
1105 } while (!IS_HT_SLAVE_CAPABILITY(temp));
1107 AmdPCIReadBits(currentPtr, 25, 21, &unitIDcnt);
1108 if ((unitIDcnt + currentBUID > 31) || ((secBus == 0) && (unitIDcnt + currentBUID > 24)))
1110 /* An error handler for the case where we run out of BUID's on a chain */
1111 if (pDat->HtBlock->AMD_CB_EventNotify)
1113 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;
1121 pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_ERROR,HT_EVENT_NCOH_BUID_EXCEED,(u8 *)&evt);
1123 STOP_HERE;
1124 break;
1126 AmdPCIWriteBits(currentPtr, 20, 16, &currentBUID);
1129 currentPtr += MAKE_SBDFO(0, 0, currentBUID, 0, 0);
1130 AmdPCIReadBits(currentPtr, 20, 16, &temp);
1131 if (temp != currentBUID)
1133 /* An error handler for this critical error */
1134 if (pDat->HtBlock->AMD_CB_EventNotify)
1136 sHtEventNcohDeviceFailed evt;
1137 evt.eSize = sizeof(sHtEventNcohDeviceFailed);
1138 evt.node = node;
1139 evt.link = link;
1140 evt.depth = depth;
1141 evt.attemptedBUID = (uint8)currentBUID;
1143 pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_ERROR,HT_EVENT_NCOH_DEVICE_FAILED,(u8 *)&evt);
1145 STOP_HERE;
1146 break;
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;
1153 lastLink = (u8)temp;
1154 lastSBDFO = currentPtr;
1156 depth++;
1157 pDat->TotalLinks++;
1158 currentBUID += unitIDcnt;
1160 if (pDat->HtBlock->AMD_CB_EventNotify)
1162 /* Provide information on automatic device results */
1163 sHtEventNcohAutoDepth evt;
1164 evt.eSize = sizeof(sHtEventNcohAutoDepth);
1165 evt.node = node;
1166 evt.link = link;
1167 evt.depth = (depth - 1);
1169 pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_INFO,HT_EVENT_NCOH_AUTO_DEPTH,(u8 *)&evt);
1175 /*----------------------------------------------------------------------------------------
1176 * void
1177 * ncInit(sMainData *pDat)
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.
1183 * Parameters:
1184 * @param[in] sMainData* pDat = our global state
1185 * ---------------------------------------------------------------------------------------
1187 static void ncInit(sMainData *pDat)
1189 u8 node, link;
1190 u8 compatLink;
1192 compatLink = pDat->nb->readSbLink(pDat->nb);
1193 processLink(0, compatLink, pDat);
1195 for (node = 0; node <= pDat->NodesDiscovered; node++)
1197 for (link = 0; link < pDat->nb->maxLinks; link++)
1199 if (pDat->HtBlock->AMD_CB_IgnoreLink && pDat->HtBlock->AMD_CB_IgnoreLink(node, link))
1200 continue; /* Skip the link */
1202 if (node == 0 && link == compatLink)
1203 continue;
1205 if (pDat->nb->readTrueLinkFailStatus(node, link, pDat, pDat->nb))
1206 continue;
1208 if (pDat->nb->verifyLinkIsNonCoherent(node, link, pDat->nb))
1209 processLink(node, link, pDat);
1214 /***************************************************************************
1215 *** Link Optimization ***
1216 ***************************************************************************/
1218 /*----------------------------------------------------------------------------------------
1219 * void
1220 * regangLinks(sMainData *pDat)
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.
1227 * Parameters:
1228 * @param[in,out] sMainData* pDat = our global state
1229 * ---------------------------------------------------------------------------------------
1231 static void regangLinks(sMainData *pDat)
1233 #ifndef HT_BUILD_NC_ONLY
1234 u8 i, j;
1235 for (i = 0; i < pDat->TotalLinks*2; i += 2)
1237 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 */
1241 /* Regang is false unless we pass all conditions below */
1242 pDat->PortList[i].SelRegang = FALSE;
1243 pDat->PortList[i+1].SelRegang = FALSE;
1245 if ( (pDat->PortList[i].Type != PORTLIST_TYPE_CPU) || (pDat->PortList[i+1].Type != PORTLIST_TYPE_CPU))
1246 continue; /* Only process cpu to cpu links */
1248 for (j = i+2; j < pDat->TotalLinks*2; j += 2)
1250 if ( (pDat->PortList[j].Type != PORTLIST_TYPE_CPU) || (pDat->PortList[j+1].Type != PORTLIST_TYPE_CPU) )
1251 continue; /* Only process cpu to cpu links */
1253 if (pDat->PortList[i].NodeID != pDat->PortList[j].NodeID)
1254 continue; /* Links must be from the same source */
1256 if (pDat->PortList[i+1].NodeID != pDat->PortList[j+1].NodeID)
1257 continue; /* Link must be to the same target */
1259 if ((pDat->PortList[i].Link & 3) != (pDat->PortList[j].Link & 3))
1260 continue; /* Ensure same source base port */
1262 if ((pDat->PortList[i+1].Link & 3) != (pDat->PortList[j+1].Link & 3))
1263 continue; /* Ensure same destination base port */
1265 if ((pDat->PortList[i].Link & 4) != (pDat->PortList[i+1].Link & 4))
1266 continue; /* Ensure sublink0 routes to sublink0 */
1268 ASSERT((pDat->PortList[j].Link & 4) == (pDat->PortList[j+1].Link & 4)); /* (therefore sublink1 routes to sublink1) */
1270 if (pDat->HtBlock->AMD_CB_SkipRegang &&
1271 pDat->HtBlock->AMD_CB_SkipRegang(pDat->PortList[i].NodeID,
1272 pDat->PortList[i].Link & 0x03,
1273 pDat->PortList[i+1].NodeID,
1274 pDat->PortList[i+1].Link & 0x03))
1276 continue; /* Skip regang */
1280 pDat->PortList[i].Link &= 0x03; /* Force to point to sublink0 */
1281 pDat->PortList[i+1].Link &= 0x03;
1282 pDat->PortList[i].SelRegang = TRUE; /* Enable link reganging */
1283 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;
1289 /* Delete PortList[j, j+1], slow but easy to debug implementation */
1290 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);
1294 /* //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; */
1298 break; /* Exit loop, advance to PortList[i+2] */
1301 #endif /* HT_BUILD_NC_ONLY */
1304 /*----------------------------------------------------------------------------------------
1305 * void
1306 * selectOptimalWidthAndFrequency(sMainData *pDat)
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.
1316 * Parameters:
1317 * @param[in,out] sMainData* pDat = our global state, port list data
1318 * ---------------------------------------------------------------------------------------
1320 static void selectOptimalWidthAndFrequency(sMainData *pDat)
1322 u8 i, j;
1323 u32 temp;
1324 u16 cbPCBFreqLimit;
1325 u8 cbPCBABDownstreamWidth;
1326 u8 cbPCBBAUpstreamWidth;
1328 for (i = 0; i < pDat->TotalLinks*2; i += 2)
1330 #if CONFIG_EXPERT && CONFIG_LIMIT_HT_SPEED_200
1331 cbPCBFreqLimit = 0x0001;
1332 #elif CONFIG_EXPERT && CONFIG_LIMIT_HT_SPEED_300
1333 cbPCBFreqLimit = 0x0003;
1334 #elif CONFIG_EXPERT && CONFIG_LIMIT_HT_SPEED_400
1335 cbPCBFreqLimit = 0x0007;
1336 #elif CONFIG_EXPERT && CONFIG_LIMIT_HT_SPEED_500
1337 cbPCBFreqLimit = 0x000F;
1338 #elif CONFIG_EXPERT && CONFIG_LIMIT_HT_SPEED_600
1339 cbPCBFreqLimit = 0x001F;
1340 #elif CONFIG_EXPERT && CONFIG_LIMIT_HT_SPEED_800
1341 cbPCBFreqLimit = 0x003F;
1342 #elif CONFIG_EXPERT && CONFIG_LIMIT_HT_SPEED_1000
1343 cbPCBFreqLimit = 0x007F;
1344 #elif CONFIG_EXPERT && CONFIG_LIMIT_HT_SPEED_1200
1345 cbPCBFreqLimit = 0x00FF;
1346 #elif CONFIG_EXPERT && CONFIG_LIMIT_HT_SPEED_1400
1347 cbPCBFreqLimit = 0x01FF;
1348 #elif CONFIG_EXPERT && CONFIG_LIMIT_HT_SPEED_1600
1349 cbPCBFreqLimit = 0x03FF;
1350 #elif CONFIG_EXPERT && CONFIG_LIMIT_HT_SPEED_1800
1351 cbPCBFreqLimit = 0x07FF;
1352 #elif CONFIG_EXPERT && CONFIG_LIMIT_HT_SPEED_2000
1353 cbPCBFreqLimit = 0x0FFF;
1354 #elif CONFIG_EXPERT && CONFIG_LIMIT_HT_SPEED_2200
1355 cbPCBFreqLimit = 0x1FFF;
1356 #elif CONFIG_EXPERT && CONFIG_LIMIT_HT_SPEED_2400
1357 cbPCBFreqLimit = 0x3FFF;
1358 #elif CONFIG_EXPERT && CONFIG_LIMIT_HT_SPEED_2600
1359 cbPCBFreqLimit = 0x7FFF;
1360 #else
1361 cbPCBFreqLimit = 0xFFFF; // Maximum allowed by autoconfiguration
1362 #endif
1364 #if CONFIG_EXPERT && CONFIG_LIMIT_HT_DOWN_WIDTH_8
1365 cbPCBABDownstreamWidth = 8;
1366 #else
1367 cbPCBABDownstreamWidth = 16;
1368 #endif
1370 #if CONFIG_EXPERT && CONFIG_LIMIT_HT_UP_WIDTH_8
1371 cbPCBBAUpstreamWidth = 8;
1372 #else
1373 cbPCBBAUpstreamWidth = 16;
1374 #endif
1376 if ( (pDat->PortList[i].Type == PORTLIST_TYPE_CPU) && (pDat->PortList[i+1].Type == PORTLIST_TYPE_CPU))
1378 if (pDat->HtBlock->AMD_CB_Cpu2CpuPCBLimits)
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
1390 else
1392 if (pDat->HtBlock->AMD_CB_IOPCBLimits)
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
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;
1411 ASSERT (temp != 0);
1412 for (j = 15; ; j--)
1414 if (temp & ((u32)1 << j))
1415 break;
1418 pDat->PortList[i].SelFrequency = j;
1419 pDat->PortList[i+1].SelFrequency = j;
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;
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;
1440 /*----------------------------------------------------------------------------------------
1441 * void
1442 * hammerSublinkFixup(sMainData *pDat)
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.
1451 * Parameters:
1452 * @param[in,out] sMainData* pDat = our global state, link state and port list
1453 * ---------------------------------------------------------------------------------------
1455 static void hammerSublinkFixup(sMainData *pDat)
1457 #ifndef HT_BUILD_NC_ONLY
1458 u8 i, j, k;
1459 BOOL changes, downgrade;
1461 u8 hiIndex;
1462 u8 hiFreq, loFreq;
1464 u32 temp;
1468 changes = FALSE;
1469 for (i = 0; i < pDat->TotalLinks*2; i++)
1471 if (pDat->PortList[i].Type != PORTLIST_TYPE_CPU) /* Must be a CPU link */
1472 continue;
1473 if (pDat->PortList[i].Link < 4) /* Only look for for sublink1's */
1474 continue;
1476 for (j = 0; j < pDat->TotalLinks*2; j++)
1478 /* Step 1. Find the matching sublink0 */
1479 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;
1486 /* Step 2. Check for an illegal frequency ratio */
1487 if (pDat->PortList[i].SelFrequency >= pDat->PortList[j].SelFrequency)
1489 hiIndex = i;
1490 hiFreq = pDat->PortList[i].SelFrequency;
1491 loFreq = pDat->PortList[j].SelFrequency;
1493 else
1495 hiIndex = j;
1496 hiFreq = pDat->PortList[j].SelFrequency;
1497 loFreq = pDat->PortList[i].SelFrequency;
1500 if (hiFreq == loFreq)
1501 break; /* The frequencies are 1:1, no need to do anything */
1503 downgrade = FALSE;
1505 if (hiFreq == 13)
1507 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 */
1510 downgrade = TRUE;
1512 else if (hiFreq == 11)
1514 if ((loFreq != 6)) /* {11, 6} 2000MHz / 1000MHz 2:1 */
1515 downgrade = TRUE;
1517 else if (hiFreq == 9)
1519 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 */
1522 downgrade = TRUE;
1524 else if (hiFreq == 7)
1526 if ((loFreq != 4) && /* { 7, 4} 1200MHz / 600MHz 2:1 */
1527 (loFreq != 0) ) /* { 7, 0} 1200MHz / 200MHz 6:1 */
1528 downgrade = TRUE;
1530 else if (hiFreq == 5)
1532 if ((loFreq != 2) && /* { 5, 2} 800MHz / 400MHz 2:1 */
1533 (loFreq != 0) ) /* { 5, 0} 800MHz / 200MHz 4:1 */
1534 downgrade = TRUE;
1536 else if (hiFreq == 2)
1538 if ((loFreq != 0)) /* { 2, 0} 400MHz / 200MHz 2:1 */
1539 downgrade = TRUE;
1541 else
1543 downgrade = TRUE; /* no legal ratios for hiFreq */
1546 /* Step 3. Downgrade the higher of the two frequencies, and set nochanges to FALSE */
1547 if (downgrade)
1549 /* 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 */
1553 temp = pDat->PortList[hiIndex].CompositeFrequencyCap;
1555 /* Remove hiFreq from the list of valid frequencies */
1556 temp = temp & ~((uint32)1 << hiFreq);
1557 ASSERT (temp != 0);
1558 pDat->PortList[hiIndex].CompositeFrequencyCap = (uint16)temp;
1559 pDat->PortList[hiIndex+1].CompositeFrequencyCap = (uint16)temp;
1561 for (k = 15; ; k--)
1563 if (temp & ((u32)1 << k))
1564 break;
1567 pDat->PortList[hiIndex].SelFrequency = k;
1568 pDat->PortList[hiIndex+1].SelFrequency = k;
1570 changes = TRUE;
1574 } while (changes); /* Repeat until a valid configuration is reached */
1575 #endif /* HT_BUILD_NC_ONLY */
1578 /*----------------------------------------------------------------------------------------
1579 * void
1580 * linkOptimization(sMainData *pDat)
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.
1588 * Parameters:
1589 * @param[in] sMainData* pDat = our global state
1590 * ---------------------------------------------------------------------------------------
1592 static void linkOptimization(sMainData *pDat)
1594 pDat->nb->gatherLinkData(pDat, pDat->nb);
1595 regangLinks(pDat);
1596 selectOptimalWidthAndFrequency(pDat);
1597 hammerSublinkFixup(pDat);
1598 pDat->nb->setLinkData(pDat, pDat->nb);
1602 /*----------------------------------------------------------------------------------------
1603 * void
1604 * trafficDistribution(sMainData *pDat)
1606 * Description:
1607 * In the case of a two node system with both sublinks used, enable the traffic
1608 * distribution feature.
1610 * Parameters:
1611 * @param[in] sMainData* pDat = our global state, port list data
1612 * ---------------------------------------------------------------------------------------
1614 static void trafficDistribution(sMainData *pDat)
1616 #ifndef HT_BUILD_NC_ONLY
1617 u32 links01, links10;
1618 u8 linkCount;
1619 u8 i;
1621 /* Traffic Distribution is only used when there are exactly two nodes in the system */
1622 if (pDat->NodesDiscovered+1 != 2)
1623 return;
1625 links01 = 0;
1626 links10 = 0;
1627 linkCount = 0;
1628 for (i = 0; i < pDat->TotalLinks*2; i += 2)
1630 if ((pDat->PortList[i].Type == PORTLIST_TYPE_CPU) && (pDat->PortList[i+1].Type == PORTLIST_TYPE_CPU))
1632 links01 |= (u32)1 << pDat->PortList[i].Link;
1633 links10 |= (u32)1 << pDat->PortList[i+1].Link;
1634 linkCount++;
1637 ASSERT(linkCount != 0);
1638 if (linkCount == 1)
1639 return; /* Don't setup Traffic Distribution if only one link is being used */
1641 pDat->nb->writeTrafficDistribution(links01, links10, pDat->nb);
1642 #endif /* HT_BUILD_NC_ONLY */
1645 /*----------------------------------------------------------------------------------------
1646 * void
1647 * tuning(sMainData *pDat)
1649 * Description:
1650 * Handle system and performance tunings, such as traffic distribution, fifo and
1651 * buffer tuning, and special config tunings.
1653 * Parameters:
1654 * @param[in] sMainData* pDat = our global state, port list data
1655 * ---------------------------------------------------------------------------------------
1657 static void tuning(sMainData *pDat)
1659 u8 i;
1661 /* See if traffic distribution can be done and do it if so
1662 * or allow system specific customization
1664 if ((pDat->HtBlock->AMD_CB_CustomizeTrafficDistribution == NULL)
1665 || !pDat->HtBlock->AMD_CB_CustomizeTrafficDistribution())
1667 trafficDistribution(pDat);
1670 /* For each node, invoke northbridge specific buffer tunings or
1671 * system specific customizations.
1673 for (i=0; i < pDat->NodesDiscovered + 1; i++)
1675 if ((pDat->HtBlock->AMD_CB_CustomizeBuffers == NULL)
1676 || !pDat->HtBlock->AMD_CB_CustomizeBuffers(i))
1678 pDat->nb->bufferOptimizations(i, pDat, pDat->nb);
1683 /*----------------------------------------------------------------------------------------
1684 * BOOL
1685 * isSanityCheckOk()
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.
1691 * Parameters:
1692 * @param[out] result BOOL = true if check is ok, false if it failed
1693 * ---------------------------------------------------------------------------------------
1695 static BOOL isSanityCheckOk(void)
1697 uint64 qValue;
1699 AmdMSRRead(APIC_Base, &qValue);
1701 return ((qValue.lo & ((u32)1 << APIC_Base_BSP)) != 0);
1704 /***************************************************************************
1705 *** HT Initialize ***
1706 ***************************************************************************/
1708 /*----------------------------------------------------------------------------------------
1709 * void
1710 * htInitialize(AMD_HTBLOCK *pBlock)
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.
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 * ---------------------------------------------------------------------------------------
1725 void amdHtInitialize(AMD_HTBLOCK *pBlock)
1727 sMainData pDat;
1728 cNorthBridge nb;
1730 if (isSanityCheckOk())
1732 newNorthBridge(0, &nb);
1734 pDat.HtBlock = pBlock;
1735 pDat.nb = &nb;
1736 pDat.sysMpCap = nb.maxNodes;
1737 nb.isCapable(0, &pDat, pDat.nb);
1738 coherentInit(&pDat);
1740 pDat.AutoBusCurrent = pBlock->AutoBusStart;
1741 pDat.UsedCfgMapEntires = 0;
1742 ncInit(&pDat);
1743 linkOptimization(&pDat);
1744 tuning(&pDat);