Initial AMD Barcelona support for rev Bx.
[coreboot.git] / src / northbridge / amd / amdht / h3ncmn.c
1 /*
2  * This file is part of the LinuxBIOS project.
3  *
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 0xF002
29 #include "h3finit.h"
30 #include "h3ffeat.h"
31 #include "h3ncmn.h"
32 #include "AsPsNb.h"
33
34
35 /*----------------------------------------------------------------------------
36  *                      DEFINITIONS AND MACROS
37  *
38  *----------------------------------------------------------------------------
39  */
40
41 /* CPU Northbridge Functions */
42 #define CPU_HTNB_FUNC_00                0
43 #define CPU_HTNB_FUNC_04                4
44 #define CPU_ADDR_FUNC_01                1
45 #define CPU_NB_FUNC_03                  3
46
47 /* Function 0 registers */
48 #define REG_ROUTE0_0X40         0x40
49 #define REG_ROUTE1_0X44         0x44
50 #define REG_NODE_ID_0X60                0x60
51 #define REG_UNIT_ID_0X64                0x64
52 #define REG_LINK_TRANS_CONTROL_0X68     0x68
53 #define REG_LINK_INIT_CONTROL_0X6C      0x6C
54 #define REG_HT_CAP_BASE_0X80            0x80
55 #define REG_HT_LINK_RETRY0_0X130        0x130
56 #define REG_HT_TRAFFIC_DIST_0X164       0x164
57 #define REG_HT_LINK_EXT_CONTROL0_0X170  0x170
58
59 #define HT_CONTROL_CLEAR_CRC            (~(3 << 8))
60
61 /* Function 1 registers */
62 #define REG_ADDR_CONFIG_MAP0_1XE0       0xE0
63 #define CPU_ADDR_NUM_CONFIG_MAPS        4
64
65 /* Function 3 registers */
66 #define REG_NB_SRI_XBAR_BUF_3X70        0x70
67 #define REG_NB_MCT_XBAR_BUF_3X78        0x78
68 #define REG_NB_FIFOPTR_3XDC             0xDC
69 #define REG_NB_CAPABILITY_3XE8          0xE8
70 #define REG_NB_CPUID_3XFC               0xFC
71 #define REG_NB_LINK_XCS_TOKEN0_3X148    0x148
72 #define REG_NB_DOWNCORE_3X190           0x190
73
74 /* Function 4 registers */
75
76
77 /*----------------------------------------------------------------------------
78  *                      TYPEDEFS AND STRUCTURES
79  *
80  *----------------------------------------------------------------------------
81  */
82 /*----------------------------------------------------------------------------
83  *                      PROTOTYPES OF LOCAL FUNCTIONS
84  *
85  *----------------------------------------------------------------------------
86  */
87
88 /***************************************************************************
89  ***                    FAMILY/NORTHBRIDGE SPECIFIC FUNCTIONS           ***
90  ***************************************************************************/
91
92 /**----------------------------------------------------------------------------------------
93  *
94  * SBDFO
95  * makeLinkBase(u8 currentNode, u8 currentLink)
96  *
97  *  Description:
98  *      Private to northbridge implementation. Return the HT Host capability base
99  *      PCI config address for a link.
100  *
101  *  Parameters:
102  *      @param[in]  u8  node    = the node this link is on
103  *      @param[in]  u8  link    = the link
104  *      @param[out] SBDFO  result  = the pci config address
105  *
106  * ---------------------------------------------------------------------------------------
107  */
108 static SBDFO makeLinkBase(u8 node, u8 link)
109 {
110         SBDFO linkBase;
111
112         /* With rev F can not be called with a 4th link or with the sublinks */
113         if (link < 4)
114                 linkBase = MAKE_SBDFO(makePCISegmentFromNode(node),
115                                 makePCIBusFromNode(node),
116                                 makePCIDeviceFromNode(node),
117                                 CPU_HTNB_FUNC_00,
118                                 REG_HT_CAP_BASE_0X80 + link*HT_HOST_CAP_SIZE);
119         else
120                 linkBase = MAKE_SBDFO(makePCISegmentFromNode(node),
121                                 makePCIBusFromNode(node),
122                                 makePCIDeviceFromNode(node),
123                                 CPU_HTNB_FUNC_04,
124                                 REG_HT_CAP_BASE_0X80 + (link-4)*HT_HOST_CAP_SIZE);
125         return linkBase;
126 }
127
128 /**----------------------------------------------------------------------------------------
129  *
130  * void
131  * setHtControlRegisterBits(SBDFO reg, u8 hiBit, u8 loBit, u32 *pValue)
132  *
133  *  Description:
134  *      Private to northbridge implementation. Provide a common routine for accessing the
135  *      HT Link Control registers (84, a4, c4, e4), to enforce not clearing the
136  *      HT CRC error bits.  Replaces direct use of AmdPCIWriteBits().
137  *      NOTE: This routine is called for IO Devices as well as CPUs!
138  *
139  *  Parameters:
140  *      @param[in]  SBDFO  reg    = the PCI config address the control register
141  *      @param[in]  u8  hiBit  = the high bit number
142  *      @param[in]  u8  loBit  = the low bit number
143  *      @param[in]  u8  pValue = the value to write to that bit range. Bit 0 => loBit.
144  *
145  * ---------------------------------------------------------------------------------------
146  */
147 static void setHtControlRegisterBits(SBDFO reg, u8 hiBit, u8 loBit, u32 *pValue)
148 {
149         u32 temp, mask;
150
151         ASSERT((hiBit < 32) && (loBit < 32) && (hiBit >= loBit) && ((reg & 0x3) == 0));
152         ASSERT((hiBit < 8) || (loBit > 9));
153
154         /* A 1<<32 == 1<<0 due to x86 SHL instruction, so skip if that is the case */
155         if ((hiBit-loBit) != 31)
156                 mask = (((u32)1 << (hiBit-loBit+1))-1);
157         else
158                 mask = (u32)0xFFFFFFFF;
159
160         AmdPCIRead(reg, &temp);
161         temp &= ~(mask << loBit);
162         temp |= (*pValue & mask) << loBit;
163         temp &= (u32)HT_CONTROL_CLEAR_CRC;
164         AmdPCIWrite(reg, &temp);
165 }
166
167 /**----------------------------------------------------------------------------------------
168  *
169  * void
170  * writeRoutingTable(u8 node, u8 target, u8 Link, cNorthBridge *nb)
171  *
172  *  Description:
173  *       This routine will modify the routing tables on the
174  *       SourceNode to cause it to route both request and response traffic to the
175  *       targetNode through the specified Link.
176  *
177  *       NOTE: This routine is to be used for early discovery and initialization.  The
178  *       final routing tables must be loaded some other way because this
179  *       routine does not address the issue of probes, or independent request
180  *       response paths.
181  *
182  *  Parameters:
183  *      @param[in]  u8  node    = the node that will have it's routing tables modified.
184  *      @param[in]  u8  target  = For routing to node target
185  *      @param[in]  u8  Link    =  Link from node to target
186  *      @param[in]  cNorthBridge *nb   = this northbridge
187  *
188  * ---------------------------------------------------------------------------------------
189  */
190
191 void writeRoutingTable(u8 node, u8 target, u8 link, cNorthBridge *nb)
192 {
193 #ifndef HT_BUILD_NC_ONLY
194         u32 temp = (nb->selfRouteResponseMask | nb->selfRouteRequestMask) << (link + 1);
195         ASSERT((node < nb->maxNodes) && (target < nb->maxNodes) && (link < nb->maxLinks));
196         AmdPCIWrite(MAKE_SBDFO(makePCISegmentFromNode(node),
197                         makePCIBusFromNode(node),
198                         makePCIDeviceFromNode(node),
199                         CPU_HTNB_FUNC_00,
200                         REG_ROUTE0_0X40 + target*4),
201                         &temp);
202 #else
203         STOP_HERE;
204 #endif
205 }
206
207 /**----------------------------------------------------------------------------------------
208  *
209  * void
210  * writeNodeID(u8 node, u8 nodeID, cNorthBridge *nb)
211  *
212  *  Description:
213  *      Modifies the NodeID register on the target node
214  *
215  *  Parameters:
216  *      @param[in] u8  node    = the node that will have its NodeID altered.
217  *      @param[in] u8  nodeID  = the new value for NodeID
218  *      @param[in] cNorthBridge *nb = this northbridge
219  *
220  * ---------------------------------------------------------------------------------------
221  */
222
223 void writeNodeID(u8 node, u8 nodeID, cNorthBridge *nb)
224 {
225         u32 temp = nodeID;
226         ASSERT((node < nb->maxNodes) && (nodeID < nb->maxNodes));
227         AmdPCIWriteBits(MAKE_SBDFO(makePCISegmentFromNode(node),
228                                 makePCIBusFromNode(node),
229                                 makePCIDeviceFromNode(node),
230                                 CPU_HTNB_FUNC_00,
231                                 REG_NODE_ID_0X60),
232                                 2, 0, &temp);
233 }
234
235 /**----------------------------------------------------------------------------------------
236  *
237  * void
238  * readDefLnk(u8 node, cNorthBridge *nb)
239  *
240  *  Description:
241  *       Read the DefLnk (the source link of the current packet)
242  *       from node
243  *
244  *  Parameters:
245  *      @param[in] u8    node    = the node that will have its NodeID altered.
246  *      @param[in] cNorthBridge *nb = this northbridge
247  *      @param[out] u8    result = The HyperTransport link where the request to
248  *                              read the default link came from.  Since this
249  *                              code is running on the BSP, this should be the link
250  *                              pointing back towards the BSP.
251  *
252  * ---------------------------------------------------------------------------------------
253  */
254
255 u8 readDefLnk(u8 node, cNorthBridge *nb)
256 {
257         u32 deflink = 0;
258         SBDFO licr;
259         u32 temp;
260
261         licr = MAKE_SBDFO(makePCISegmentFromNode(node),
262                         makePCIBusFromNode(node),
263                         makePCIDeviceFromNode(node),
264                         CPU_HTNB_FUNC_00,
265                         REG_LINK_INIT_CONTROL_0X6C);
266
267         ASSERT((node < nb->maxNodes));
268         AmdPCIReadBits(licr, 3, 2, &deflink);
269         AmdPCIReadBits(licr, 8, 8, &temp);      /* on rev F, this bit is reserved == 0 */
270         deflink |= temp << 2;
271         return (u8)deflink;
272 }
273
274 /**----------------------------------------------------------------------------------------
275  *
276  * void
277  * enableRoutingTables(u8 node, cNorthBridge *nb)
278  *
279  *  Description:
280  *      Turns routing tables on for a given node
281  *
282  *  Parameters:
283  *      @param[in]  u8    node     = the node that will have it's routing tables enabled
284  *      @param[in]  cNorthBridge *nb  = this northbridge
285  *
286  * ---------------------------------------------------------------------------------------
287  */
288
289 void enableRoutingTables(u8 node, cNorthBridge *nb)
290 {
291         u32 temp = 0;
292         ASSERT((node < nb->maxNodes));
293         AmdPCIWriteBits(MAKE_SBDFO(makePCISegmentFromNode(node),
294                                 makePCIBusFromNode(node),
295                                 makePCIDeviceFromNode(node),
296                                 CPU_HTNB_FUNC_00,
297                                 REG_LINK_INIT_CONTROL_0X6C),
298                                 0, 0, &temp);
299 }
300
301
302 /**----------------------------------------------------------------------------------------
303  *
304  * void
305  * verifyLinkIsCoherent(u8 node, u8 Link, cNorthBridge *nbk)
306  *
307  *  Description:
308  *      Verify that the link is coherent, connected, and ready
309  *
310  *  Parameters:
311  *      @param[in]   u8  node      = the node that will be examined
312  *      @param[in]   u8  link      = the link on that Node to examine
313  *      @param[in]   cNorthBridge *nb = this northbridge
314  *      @param[out]  u8  result    = true - The link has the following status
315  *                                linkCon=1,           Link is connected
316  *                                InitComplete=1,      Link initialization is complete
317  *                                NC=0,                Link is coherent
318  *                                UniP-cLDT=0,         Link is not Uniprocessor cLDT
319  *                                LinkConPend=0        Link connection is not pending
320  *                                false- The link has some other status
321  *
322  * ---------------------------------------------------------------------------------------
323  */
324
325 BOOL verifyLinkIsCoherent(u8 node, u8 link, cNorthBridge *nb)
326 {
327 #ifndef HT_BUILD_NC_ONLY
328
329         u32 linkType;
330         SBDFO linkBase;
331
332         ASSERT((node < nb->maxNodes) && (link < nb->maxLinks));
333
334         linkBase = makeLinkBase(node, link);
335
336         // FN0_98/A4/C4 = LDT Type Register
337         AmdPCIRead(linkBase + HTHOST_LINK_TYPE_REG, &linkType);
338
339         // Verify LinkCon=1, InitComplete=1, NC=0, UniP-cLDT=0, LinkConPend=0
340         return (linkType & HTHOST_TYPE_MASK) ==  HTHOST_TYPE_COHERENT;
341 #else
342         return 0;
343 #endif /* HT_BUILD_NC_ONLY */
344 }
345
346 /**----------------------------------------------------------------------------------------
347  *
348  * bool
349  * readTrueLinkFailStatus(u8 node, u8 link, sMainData *pDat, cNorthBridge *nb)
350  *
351  *  Description:
352  *      Return the LinkFailed status AFTER an attempt is made to clear the bit.
353  *      Also, call event notify if a Hardware Fault caused a synch flood on a previous boot.
354  *
355  *      The table below summarizes correct responses of this routine.
356  *      Family    before    after    unconnected    Notify?    return
357  *        0F         0       0          0             No         0
358  *        0F         1       0          0             Yes        0
359  *        0F         1       1          X             No         1
360  *        10         0       0          0             No         0
361  *        10         1       0          0             Yes        0
362  *        10         1       0          3             No         1
363  *
364  *  Parameters:
365  *      @param[in]    u8  node      = the node that will be examined
366  *      @param[in]    u8  link      = the link on that node to examine
367  *      @param[in]    u8  sMainData = access to call back routine
368  *      @param[in]    cNorthBridge *nb = this northbridge
369  *      @param[out]   u8  result    = true - the link is not connected or has hard error
370  *                                      false- if the link is connected
371  *
372  * ---------------------------------------------------------------------------------------
373  */
374 BOOL readTrueLinkFailStatus(u8 node, u8 link, sMainData *pDat, cNorthBridge *nb)
375 {
376         u32 before, after, unconnected, crc;
377         SBDFO linkBase;
378
379         ASSERT((node < nb->maxNodes) && (link < nb->maxLinks));
380
381         linkBase = makeLinkBase(node, link);
382
383         /* Save the CRC status before doing anything else.
384          * Read, Clear, the Re-read the error bits in the Link Control Register
385          * FN0_84/A4/C4[4] = LinkFail bit
386          * and the connection status, TransOff and EndOfChain
387          */
388         AmdPCIReadBits(linkBase + HTHOST_LINK_CONTROL_REG, 9, 8, &crc);
389         AmdPCIReadBits(linkBase + HTHOST_LINK_CONTROL_REG, 4, 4, &before);
390         setHtControlRegisterBits(linkBase + HTHOST_LINK_CONTROL_REG, 4, 4, &before);
391         AmdPCIReadBits(linkBase + HTHOST_LINK_CONTROL_REG, 4, 4, &after);
392         AmdPCIReadBits(linkBase + HTHOST_LINK_CONTROL_REG, 7, 6, &unconnected);
393
394         if (before != after)
395         {
396                 if (!unconnected)
397                 {
398                         if (crc != 0)
399                         {
400                                 /* A synch flood occurred due to HT CRC */
401                                 if (pDat->HtBlock->AMD_CB_EventNotify)
402                                 {
403                                         /* Pass the node and link on which the generic synch flood event occurred. */
404                                         sHtEventHWHtCrc evt = {sizeof(sHtEventHWHtCrc), node, link, (u8)crc};
405
406                                         pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_HW_FAULT,
407                                                                         HT_EVENT_HW_HTCRC,
408                                                                         (u8 *)&evt);
409                                 }
410                         }
411                         else
412                         {
413                                 /* Some synch flood occurred */
414                                 if (pDat->HtBlock->AMD_CB_EventNotify)
415                                 {
416                                         /* Pass the node and link on which the generic synch flood event occurred. */
417                                         sHtEventHWSynchFlood evt = {sizeof(sHtEventHWSynchFlood), node, link};
418
419                                         pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_HW_FAULT,
420                                                                         HT_EVENT_HW_SYNCHFLOOD,
421                                                                         (u8 *)&evt);
422                                 }
423                         }
424                 }
425         }
426         return ((after != 0) || unconnected);
427 }
428
429
430 /**----------------------------------------------------------------------------------------
431  *
432  * u8
433  * readToken(u8 node, cNorthBridge *nb)
434  *
435  *  Description:
436  *      Read the token stored in the scratchpad register
437  *      NOTE: The location used to store the token is arbitrary.  The only
438  *      requirement is that the location warm resets to zero, and that
439  *      using it will have no ill-effects during HyperTransport initialization.
440  *
441  *  Parameters:
442  *      @param[in]  u8  node      = the node that will be examined
443  *      @param[in]  cNorthBridge *nb = this northbridge
444  *      @param[out] u8  result    = the Token read from the node
445  *
446  * ---------------------------------------------------------------------------------------
447  */
448 u8 readToken(u8 node, cNorthBridge *nb)
449 {
450         u32 temp;
451
452         ASSERT((node < nb->maxNodes));
453         /* Use CpuCnt as a scratch register */
454         /* Limiting use to 4 bits makes code GH to rev F compatible. */
455         AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(node),
456                                 makePCIBusFromNode(node),
457                                 makePCIDeviceFromNode(node),
458                                 CPU_HTNB_FUNC_00,
459                                 REG_NODE_ID_0X60),
460                                 19, 16, &temp);
461
462         return (u8)temp;
463 }
464
465
466 /**----------------------------------------------------------------------------------------
467  *
468  * void
469  * writeToken(u8 node, u8 Value, cNorthBridge *nb)
470  *
471  *  Description:
472  *      Write the token stored in the scratchpad register
473  *      NOTE: The location used to store the token is arbitrary.  The only
474  *      requirement is that the location warm resets to zero, and that
475  *      using it will have no ill-effects during HyperTransport initialization.
476  *      Limiting use to 4 bits makes code GH to rev F compatible.
477  *
478  *  Parameters:
479  *      @param[in]  u8  node  = the node that will be examined
480  *      @param[in]  cNorthBridge *nb  = this northbridge
481  *
482  * ---------------------------------------------------------------------------------------
483  */
484 void writeToken(u8 node, u8 value, cNorthBridge *nb)
485 {
486         u32 temp = value;
487         ASSERT((node < nb->maxNodes));
488         /* Use CpuCnt as a scratch register */
489         /* Limiting use to 4 bits makes code GH to rev F compatible. */
490         AmdPCIWriteBits(MAKE_SBDFO(makePCISegmentFromNode(node),
491                                         makePCIBusFromNode(node),
492                                         makePCIDeviceFromNode(node),
493                                         CPU_HTNB_FUNC_00,
494                                         REG_NODE_ID_0X60),
495                                         19, 16, &temp);
496 }
497
498 /**----------------------------------------------------------------------------------------
499  *
500  * u8
501  * fam0FGetNumCoresOnNode(u8 node, cNorthBridge *nb)
502  *
503  *  Description:
504  *      Return the number of cores (1 based count) on node.
505  *
506  *  Parameters:
507  *      @param[in]  u8  node      = the node that will be examined
508  *      @param[in]  cNorthBridge *nb = this northbridge
509  *      @param[out] u8  result    = the number of cores
510  *
511  * ---------------------------------------------------------------------------------------
512  */
513 u8 fam0FGetNumCoresOnNode(u8 node, cNorthBridge *nb)
514 {
515         u32 temp;
516
517         ASSERT((node < nb->maxNodes));
518         /* Read CmpCap */
519         AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(node),
520                         makePCIBusFromNode(node),
521                         makePCIDeviceFromNode(node),
522                         CPU_NB_FUNC_03,
523                         REG_NB_CAPABILITY_3XE8),
524                         13, 12, &temp);
525
526         /* and add one */
527         return (u8)(temp+1);
528 }
529
530 /**----------------------------------------------------------------------------------------
531  *
532  * u8
533  * fam10GetNumCoresOnNode(u8 node, cNorthBridge *nb)
534  *
535  *  Description:
536  *      Return the number of cores (1 based count) on node.
537  *
538  *  Parameters:
539  *      @param[in]  u8  node      = the node that will be examined
540  *      @param[in]  cNorthBridge *nb = this northbridge
541  *      @param[out] u8  result    = the number of cores
542  *
543  * ---------------------------------------------------------------------------------------
544  */
545 u8 fam10GetNumCoresOnNode(u8 node, cNorthBridge *nb)
546 {
547         u32 temp, leveling, cores;
548         u8 i;
549
550         ASSERT((node < nb->maxNodes));
551         /* Read CmpCap */
552         AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(node),
553                                 makePCIBusFromNode(node),
554                                 makePCIDeviceFromNode(node),
555                                 CPU_NB_FUNC_03,
556                                 REG_NB_CAPABILITY_3XE8),
557                                 13, 12, &temp);
558
559         /* Support Downcoring */
560         cores = temp + 1;
561         AmdPCIReadBits (MAKE_SBDFO(makePCISegmentFromNode(node),
562                                         makePCIBusFromNode(node),
563                                         makePCIDeviceFromNode(node),
564                                         CPU_NB_FUNC_03,
565                                         REG_NB_DOWNCORE_3X190),
566                                         3, 0, &leveling);
567         for (i=0; i<cores; i++)
568         {
569                 if (leveling & ((u32) 1 << i))
570                 {
571                         temp--;
572                 }
573         }
574         return (u8)(temp+1);
575 }
576
577 /**----------------------------------------------------------------------------------------
578  *
579  * void
580  * setTotalNodesAndCores(u8 node, u8 totalNodes, u8 totalCores, cNorthBridge *nb)
581  *
582  *  Description:
583  *      Write the total number of cores and nodes to the node
584  *
585  *  Parameters:
586  *      @param[in]  u8  node   = the node that will be examined
587  *      @param[in]  u8  totalNodes  = the total number of nodes
588  *      @param[in]  u8  totalCores  = the total number of cores
589  *      @param[in]  cNorthBridge *nb   = this northbridge
590  *
591  * ---------------------------------------------------------------------------------------
592  */
593 void setTotalNodesAndCores(u8 node, u8 totalNodes, u8 totalCores, cNorthBridge *nb)
594 {
595         SBDFO nodeIDReg;
596         u32 temp;
597
598         ASSERT((node < nb->maxNodes) && (totalNodes <= nb->maxNodes));
599         nodeIDReg = MAKE_SBDFO(makePCISegmentFromNode(node),
600                                 makePCIBusFromNode(node),
601                                 makePCIDeviceFromNode(node),
602                                 CPU_HTNB_FUNC_00,
603                                 REG_NODE_ID_0X60);
604
605         temp = totalCores-1;
606         /* Rely on max number of nodes:cores for rev F and GH to make
607          * this code work, even though we write reserved bit 20 on rev F it will be
608          * zero in that case.
609          */
610         AmdPCIWriteBits(nodeIDReg, 20, 16, &temp);
611         temp = totalNodes-1;
612         AmdPCIWriteBits(nodeIDReg, 6,  4, &temp);
613 }
614
615 /**----------------------------------------------------------------------------------------
616  *
617  * void
618  * limitNodes(u8 node, cNorthBridge *nb)
619  *
620  *  Description:
621  *      Limit coherent config accesses to cpus as indicated by nodecnt.
622  *
623  *  Parameters:
624  *      @param[in]  u8  node  = the node that will be examined
625  *      @param[in]  cNorthBridge *nb  = this northbridge
626  *
627  * ---------------------------------------------------------------------------------------
628  */
629 void limitNodes(u8 node, cNorthBridge *nb)
630 {
631         u32 temp = 1;
632         ASSERT((node < nb->maxNodes));
633         AmdPCIWriteBits(MAKE_SBDFO(makePCISegmentFromNode(node),
634                                 makePCIBusFromNode(node),
635                                 makePCIDeviceFromNode(node),
636                                 CPU_HTNB_FUNC_00,
637                                 REG_LINK_TRANS_CONTROL_0X68),
638                                 15, 15, &temp);
639 }
640
641 /**----------------------------------------------------------------------------------------
642  *
643  * void
644  * writeFullRoutingTable(u8 node, u8 target, u8 reqLink, u8 rspLink, u32 BClinks, cNorthBridge *nb)
645  *
646  *  Description:
647  *      Write the routing table entry for node to target, using the request link, response
648  *      link, and broadcast links provided.
649  *
650  *  Parameters:
651  *      @param[in]  u8  node   = the node that will be examined
652  *      @param[in]  u8  target   = the target node for these routes
653  *      @param[in]  u8  reqLink  = the link for requests to target
654  *      @param[in]  u8  rspLink  = the link for responses to target
655  *      @param[in]  u32 bClinks  = the broadcast links
656  *      @param[in]  cNorthBridge *nb  = this northbridge
657  *
658  * ---------------------------------------------------------------------------------------
659  */
660 void writeFullRoutingTable(u8 node, u8 target, u8 reqLink, u8 rspLink, u32 bClinks, cNorthBridge *nb)
661 {
662 #ifndef HT_BUILD_NC_ONLY
663         u32 value = 0;
664
665         ASSERT((node < nb->maxNodes) && (target < nb->maxNodes));
666         if (reqLink == ROUTETOSELF)
667                 value |= nb->selfRouteRequestMask;
668         else
669                 value |= nb->selfRouteRequestMask << (reqLink+1);
670
671         if (rspLink == ROUTETOSELF)
672                 value |= nb->selfRouteResponseMask;
673         else
674                 value |= nb->selfRouteResponseMask << (rspLink+1);
675
676         /* Allow us to accept a Broadcast ourselves, then set broadcasts for routes */
677         value |= (u32)1 << nb->broadcastSelfBit;
678         value |= (u32)bClinks << (nb->broadcastSelfBit + 1);
679
680         AmdPCIWrite(MAKE_SBDFO(makePCISegmentFromNode(node),
681                                 makePCIBusFromNode(node),
682                                 makePCIDeviceFromNode(node),
683                                 CPU_HTNB_FUNC_00,
684                                 REG_ROUTE0_0X40 + target*4), &value);
685 #else
686         STOP_HERE;
687 #endif /* HT_BUILD_NC_ONLY */
688 }
689
690 /**----------------------------------------------------------------------------------------
691  *
692  * static u32
693  * makeKey(u8 currentNode)
694  *
695  *  Description:
696  *      Private routine to northbridge code.
697  *      Determine whether a node is compatible with the discovered configuration so
698  *      far.  Currently, that means the family, extended family of the new node are the
699  *      same as the BSP's.
700  *
701  *  Parameters:
702  *      @param[in]  u8   node   = the node
703  *      @param[out] u32  result = the key value
704  *
705  * ---------------------------------------------------------------------------------------
706  */
707 static u32 makeKey(u8 node)
708 {
709         u32 extFam, baseFam;
710         AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(node),
711                                 makePCIBusFromNode(node),
712                                 makePCIDeviceFromNode(node),
713                                 CPU_NB_FUNC_03,
714                                 REG_NB_CPUID_3XFC),
715                                 27, 20, &extFam);
716         AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(node),
717                                 makePCIBusFromNode(node),
718                                 makePCIDeviceFromNode(node),
719                                 CPU_NB_FUNC_03,
720                                 REG_NB_CPUID_3XFC),
721                                 11, 8, &baseFam);
722         return ((u32)(baseFam << 8) | extFam);
723 }
724
725
726 /**----------------------------------------------------------------------------------------
727  *
728  * BOOL
729  * isCompatible(u8 currentNode, cNorthBridge *nb)
730  *
731  *  Description:
732  *      Determine whether a node is compatible with the discovered configuration so
733  *      far.  Currently, that means the family, extended family of the new node are the
734  *      same as the BSP's.
735  *
736  *  Parameters:
737  *      @param[in]  u8  node   = the node
738  *      @param[in]  cNorthBridge *nb  = this northbridge
739  *      @param[out] BOOL   result = true: the new is compatible, false: it is not
740  *
741  * ---------------------------------------------------------------------------------------
742  */
743 BOOL isCompatible(u8 node, cNorthBridge *nb)
744 {
745         return (makeKey(node) == nb->compatibleKey);
746 }
747
748 /**----------------------------------------------------------------------------------------
749  *
750  * BOOL
751  * fam0fIsCapable(u8 node, sMainData *pDat, cNorthBridge *nb)
752  *
753  *  Description:
754  *      Get node capability and update the minimum supported system capability.
755  *      Return whether the current configuration exceeds the capability.
756  *
757  *  Parameters:
758  *      @param[in] u8  node      = the node
759  *      @param[in,out]  sMainData *pDat = sysMpCap (updated) and NodesDiscovered
760  *      @param[in] cNorthBridge *nb = this northbridge
761  *      @param[out] BOOL  result    = true: system is capable of current config.
762  *                            false: system is not capable of current config.
763  *
764  * ---------------------------------------------------------------------------------------
765  */
766 BOOL fam0fIsCapable(u8 node, sMainData *pDat, cNorthBridge *nb)
767 {
768 #ifndef HT_BUILD_NC_ONLY
769         u32 temp;
770         u8 maxNodes;
771
772         ASSERT(node < nb->maxNodes);
773
774         AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(node),
775                                 makePCIBusFromNode(node),
776                                 makePCIDeviceFromNode(node),
777                                 CPU_NB_FUNC_03,
778                                 REG_NB_CAPABILITY_3XE8),
779                                 2, 1, &temp);
780         if (temp > 1)
781         {
782                 maxNodes = 8;
783         } else {
784                 if (temp == 1)
785                 {
786                         maxNodes = 2;
787                 } else {
788                         maxNodes = 1;
789                 }
790         }
791         if (pDat->sysMpCap > maxNodes)
792         {
793                  pDat->sysMpCap = maxNodes;
794         }
795         /* Note since sysMpCap is one based and NodesDiscovered is zero based, equal is false */
796         return (pDat->sysMpCap > pDat->NodesDiscovered);
797 #else
798         return 1;
799 #endif
800 }
801
802 /**----------------------------------------------------------------------------------------
803  *
804  * BOOL
805  * fam10IsCapable(u8 node, sMainData *pDat, cNorthBridge *nb)
806  *
807  *  Description:
808  *      Get node capability and update the minimum supported system capability.
809  *      Return whether the current configuration exceeds the capability.
810  *
811  *  Parameters:
812  *      @param[in] u8  node   = the node
813  *      @param[in,out] sMainData *pDat = sysMpCap (updated) and NodesDiscovered
814  *      @param[in]  cNorthBridge *nb   = this northbridge
815  *      @param[out] BOOL  result = true: system is capable of current config.
816  *                         false: system is not capable of current config.
817  *
818  * ---------------------------------------------------------------------------------------
819  */
820 BOOL fam10IsCapable(u8 node, sMainData *pDat, cNorthBridge *nb)
821 {
822 #ifndef HT_BUILD_NC_ONLY
823         u32 temp;
824         u8 maxNodes;
825
826         ASSERT(node < nb->maxNodes);
827
828         AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(node),
829                                 makePCIBusFromNode(node),
830                                 makePCIDeviceFromNode(node),
831                                 CPU_NB_FUNC_03,
832                                 REG_NB_CAPABILITY_3XE8),
833                                 18, 16, &temp);
834
835         if (temp != 0)
836         {
837                 maxNodes = (1 << (~temp & 0x3));  /* That is, 1, 2, 4, or 8 */
838         }
839         else
840         {
841                 maxNodes = 8;
842         }
843
844         if (pDat->sysMpCap > maxNodes)
845         {
846                 pDat->sysMpCap = maxNodes;
847         }
848         /* Note since sysMpCap is one based and NodesDiscovered is zero based, equal is false */
849         return (pDat->sysMpCap > pDat->NodesDiscovered);
850 #else
851         return 1;
852 #endif
853 }
854
855 /**----------------------------------------------------------------------------------------
856  *
857  * void
858  * fam0fStopLink(u8 currentNode, u8 currentLink, cNorthBridge *nb)
859  *
860  *  Description:
861  *      Disable a cHT link on node by setting F0x[E4, C4, A4, 84][TransOff, EndOfChain]=1
862  *
863  *  Parameters:
864  *      @param[in]  u8  node      = the node this link is on
865  *      @param[in]  u8  link      = the link to stop
866  *      @param[in]  cNorthBridge *nb = this northbridge
867  *
868  * ---------------------------------------------------------------------------------------
869  */
870 void fam0fStopLink(u8 node, u8 link, cNorthBridge *nb)
871 {
872 #ifndef HT_BUILD_NC_ONLY
873         u32 temp;
874         SBDFO linkBase;
875
876         ASSERT((node < nb->maxNodes) && (link < nb->maxLinks));
877
878         linkBase = makeLinkBase(node, link);
879
880         /* Set TransOff, EndOfChain */
881         temp = 3;
882         setHtControlRegisterBits(linkBase + HTHOST_LINK_CONTROL_REG, 7, 6, &temp);
883 #endif
884 }
885
886 /**----------------------------------------------------------------------------------------
887  *
888  * void
889  * commonVoid()
890  *
891  *  Description:
892  *      Nothing.
893  *
894  *  Parameters:
895  *              None.
896  *
897  * ---------------------------------------------------------------------------------------
898  */
899 void commonVoid()
900 {
901 }
902
903 /**----------------------------------------------------------------------------------------
904  *
905  * BOOL
906  * commonReturnFalse()
907  *
908  *  Description:
909  *      Return False.
910  *
911  *  Parameters:
912  *           @param[out]    BOOL     result        = false
913  * ---------------------------------------------------------------------------------------
914  */
915 BOOL commonReturnFalse()
916 {
917         return 0;
918 }
919
920 /***************************************************************************
921  ***                    Non-coherent init code                            ***
922  ***                    Northbridge access routines                       ***
923  ***************************************************************************/
924
925 /**----------------------------------------------------------------------------------------
926  *
927  * u8
928  * readSbLink(cNorthBridge *nb)
929  *
930  *  Description:
931  *       Return the link to the Southbridge
932  *
933  *  Parameters:
934  *      @param[in]  cNorthBridge *nb = this northbridge
935  *      @param[out] u8    results = the link to the southbridge
936  *
937  * ---------------------------------------------------------------------------------------
938  */
939 u8 readSbLink(cNorthBridge *nb)
940 {
941         u32 temp;
942         AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(0),
943                                 makePCIBusFromNode(0),
944                                 makePCIDeviceFromNode(0),
945                                 CPU_HTNB_FUNC_00,
946                                 REG_UNIT_ID_0X64),
947                                 10, 8, &temp);
948         return (u8)temp;
949 }
950
951 /**----------------------------------------------------------------------------------------
952  *
953  * BOOL
954  * verifyLinkIsNonCoherent(u8 node, u8 link, cNorthBridge *nb)
955  *
956  *  Description:
957  *       Verify that the link is non-coherent, connected, and ready
958  *
959  *  Parameters:
960  *      @param[in]  u8  node   = the node that will be examined
961  *      @param[in]  u8  link   = the Link on that node to examine
962  *      @param[in]  cNorthBridge *nb = this northbridge
963  *      @param[out] u8  results   = true - The link has the following status
964  *                                      LinkCon=1,     Link is connected
965  *                                      InitComplete=1,Link initilization is complete
966  *                                      NC=1,          Link is coherent
967  *                                      UniP-cLDT=0,   Link is not Uniprocessor cLDT
968  *                                      LinkConPend=0  Link connection is not pending
969  *                                      false- The link has some other status
970  *
971  * ---------------------------------------------------------------------------------------
972  */
973 BOOL verifyLinkIsNonCoherent(u8 node, u8 link, cNorthBridge *nb)
974 {
975         u32 linkType;
976         SBDFO linkBase;
977
978         ASSERT((node < nb->maxNodes) && (link < nb->maxLinks));
979
980         linkBase = makeLinkBase(node, link);
981
982         /* FN0_98/A4/C4 = LDT Type Register */
983         AmdPCIRead(linkBase + HTHOST_LINK_TYPE_REG, &linkType);
984
985         /* Verify linkCon=1, InitComplete=1, NC=0, UniP-cLDT=0, LinkConPend=0 */
986         return (linkType & HTHOST_TYPE_MASK) ==  HTHOST_TYPE_NONCOHERENT;
987 }
988
989 /**----------------------------------------------------------------------------------------
990  *
991  * void
992  * ht3SetCFGAddrMap(u8 cfgMapIndex, u8 secBus, u8 subBus, u8 targetNode, u8 targetLink, sMainData *pDat, cNorthBridge *nb)
993  *
994  *  Description:
995  *       Configure and enable config access to a non-coherent chain for the given bus range.
996  *
997  *  Parameters:
998  *      @param[in] u8 cfgRouteIndex = the map entry to set
999  *      @param[in] u8 secBus      = The secondary bus number to use
1000  *      @param[in] u8 subBus      = The subordinate bus number to use
1001  *      @param[in] u8 targetNode  = The node  that shall be the recipient of the traffic
1002  *      @param[in] u8 targetLink  = The link that shall be the recipient of the traffic
1003  *      @param[in] sMainData* pDat   = our global state
1004  *      @param[in] cNorthBridge *nb  = this northbridge
1005  *
1006  * ---------------------------------------------------------------------------------------
1007  */
1008 void  ht3SetCFGAddrMap(u8 cfgMapIndex, u8 secBus, u8 subBus, u8 targetNode, u8 targetLink, sMainData *pDat, cNorthBridge *nb)
1009 {
1010         u8 curNode;
1011         SBDFO linkBase;
1012         u32 temp;
1013
1014         linkBase = makeLinkBase(targetNode, targetLink);
1015
1016         ASSERT(secBus <= subBus);
1017         temp = secBus;
1018         AmdPCIWriteBits(linkBase + HTHOST_ISOC_REG, 15, 8, &temp);
1019
1020         /* For target link, note that rev F uses bits 9:8 and only with GH is bit 10
1021          * set to indicate a sublink.  For node, we are currently not supporting Extended
1022          * routing tables.
1023          */
1024         temp = ((u32)subBus << 24) + ((u32)secBus << 16) + ((u32)targetLink << 8)
1025                 + ((u32)targetNode << 4) + (u32)3;
1026         for (curNode = 0; curNode < pDat->NodesDiscovered+1; curNode++)
1027                 AmdPCIWrite(MAKE_SBDFO(makePCISegmentFromNode(curNode),
1028                                         makePCIBusFromNode(curNode),
1029                                         makePCIDeviceFromNode(curNode),
1030                                         CPU_ADDR_FUNC_01,
1031                                         REG_ADDR_CONFIG_MAP0_1XE0 + 4*cfgMapIndex),
1032                                         &temp);
1033 }
1034
1035 /**----------------------------------------------------------------------------------------
1036  *
1037  * void
1038  * ht1SetCFGAddrMap(u8 cfgMapIndex, u8 secBus, u8 subBus, u8 targetNode, u8 targetLink, sMainData *pDat, cNorthBridge *nb)
1039  *
1040  *  Description:
1041  *       Configure and enable config access to a non-coherent chain for the given bus range.
1042  *
1043  *  Parameters:
1044  *      @param[in] u8  cfgMapIndex = the map entry to set
1045  *      @param[in] u8  secBus      = The secondary bus number to use
1046  *      @param[in] u8  subBus      = The subordinate bus number to use
1047  *      @param[in] u8  targetNode  = The node  that shall be the recipient of the traffic
1048  *      @param[in] u8  targetLink  = The link that shall be the recipient of the traffic
1049  *      @param[in] sMainData*  pDat   = our global state
1050  *      @param[in] cNorthBridge *nb   = this northbridge
1051  *
1052  * ---------------------------------------------------------------------------------------
1053  */
1054 void ht1SetCFGAddrMap(u8 cfgMapIndex, u8 secBus, u8 subBus, u8 targetNode, u8 targetLink, sMainData *pDat, cNorthBridge *nb)
1055 {
1056         u8 curNode;
1057         SBDFO linkBase;
1058         u32 temp;
1059
1060         linkBase = makeLinkBase(targetNode, targetLink);
1061
1062         ASSERT(secBus <= subBus);
1063         temp = secBus;
1064         AmdPCIWriteBits(linkBase + HTHOST_ISOC_REG, 15, 8, &temp);
1065
1066         temp = subBus;
1067         AmdPCIWriteBits(linkBase + HTHOST_ISOC_REG, 23, 16, &temp);
1068
1069         /* For target link, note that rev F uses bits 9:8 and only with GH is bit 10
1070          * set to indicate a sublink.  For node, we are currently not supporting Extended
1071          * routing tables.
1072          */
1073         temp = ((u32)subBus << 24) + ((u32)secBus << 16) + ((u32)targetLink << 8)
1074                 + ((u32)targetNode << 4) + (u32)3;
1075         for (curNode = 0; curNode < pDat->NodesDiscovered+1; curNode++)
1076                  AmdPCIWrite(MAKE_SBDFO(makePCISegmentFromNode(curNode),
1077                                         makePCIBusFromNode(curNode),
1078                                         makePCIDeviceFromNode(curNode),
1079                                         CPU_ADDR_FUNC_01,
1080                                         REG_ADDR_CONFIG_MAP0_1XE0 + 4*cfgMapIndex),
1081                                         &temp);
1082 }
1083
1084 /***************************************************************************
1085  ***                             Link Optimization                        ***
1086  ***************************************************************************/
1087
1088 /**----------------------------------------------------------------------------------------
1089  *
1090  * u8
1091  * convertBitsToWidth(u8 value, cNorthBridge *nb)
1092  *
1093  *  Description:
1094  *       Given the bits set in the register field, return the width it represents
1095  *
1096  *  Parameters:
1097  *      @param[in]  u8  value   = The bits for the register
1098  *      @param[in]  cNorthBridge *nb = this northbridge
1099  *      @param[out] u8  results = The width
1100  *
1101  * ---------------------------------------------------------------------------------------
1102  */
1103 u8 convertBitsToWidth(u8 value, cNorthBridge *nb)
1104 {
1105         if (value == 1) {
1106                 return 16;
1107         } else if (value == 0) {
1108                 return 8;
1109         } else if (value == 5) {
1110                 return 4;
1111         } else if (value == 4) {
1112                 return 2;
1113         }
1114         STOP_HERE; // This is an error internal condition
1115
1116         return 0xFF;    // make the compiler happy.
1117
1118 }
1119
1120 /**----------------------------------------------------------------------------------------
1121  *
1122  * u8
1123  * convertWidthToBits(u8 value, cNorthBridge *nb)
1124  *
1125  *  Description:
1126  *      Translate a desired width setting to the bits to set in the register field
1127  *
1128  *  Parameters:
1129  *      @param[in]  u8  value     = The width
1130  *      @param[in]  cNorthBridge *nb = this northbridge
1131  *      @param[out] u8  results   = The bits for the register
1132  *
1133  * ---------------------------------------------------------------------------------------
1134  */
1135 u8 convertWidthToBits(u8 value, cNorthBridge *nb)
1136 {
1137         if (value == 16) {
1138                 return 1;
1139         } else if (value == 8) {
1140                 return 0;
1141         } else if (value == 4) {
1142                 return 5;
1143         } else if (value == 2) {
1144                 return 4;
1145         }
1146         STOP_HERE; // This is an internal error condition
1147
1148         return 0xFF;    // make the compiler happy.
1149 }
1150
1151 /**----------------------------------------------------------------------------------------
1152  *
1153  * u16
1154  * ht1NorthBridgeFreqMask(u8 NodeID, cNorthBridge *nb)
1155  *
1156  *  Description:
1157  *      Return a mask that eliminates HT frequencies that cannot be used due to a slow
1158  *      northbridge frequency.
1159  *
1160  *  Parameters:
1161  *      @param[in]  u8  node      = Result could (later) be for a specific node
1162  *      @param[in]  cNorthBridge *nb = this northbridge
1163  *      @param[out] u16 results   = Frequency mask
1164  *
1165  * ---------------------------------------------------------------------------------------
1166  */
1167 u16 ht1NorthBridgeFreqMask(u8 node, cNorthBridge *nb)
1168 {
1169         /* only up to HT1 speeds */
1170         return (HT_FREQUENCY_LIMIT_HT1_ONLY);
1171 }
1172
1173 /**----------------------------------------------------------------------------------------
1174  *
1175  * u16
1176  * fam10NorthBridgeFreqMask(u8 NodeID, cNorthBridge *nb)
1177  *
1178  *  Description:
1179  *      Return a mask that eliminates HT frequencies that cannot be used due to a slow
1180  *      northbridge frequency.
1181  *
1182  *  Parameters:
1183  *      @param[in]  u8    node     = Result could (later) be for a specific node
1184  *      @param[in]  cNorthBridge *nb  = this northbridge
1185  *      @param[out] u16   results  = Frequency mask
1186  *
1187  * ---------------------------------------------------------------------------------------
1188  */
1189 u16 fam10NorthBridgeFreqMask(u8 node, cNorthBridge *nb)
1190 {
1191         u8 nbCOF;
1192         u16 supported;
1193
1194         nbCOF = getMinNbCOF();
1195         /*
1196          * nbCOF is minimum northbridge speed in hundreds of MHz.
1197          * HT can not go faster than the minimum speed of the northbridge.
1198          */
1199         if ((nbCOF >= 6) && (nbCOF <= 26))
1200         {
1201                 /* Convert frequency to bit and all less significant bits,
1202                  * by setting next power of 2 and subtracting 1.
1203                  */
1204                 supported = ((u16)1 << ((nbCOF >> 1) + 2)) - 1;
1205         }
1206         else if (nbCOF > 26)
1207         {
1208                 supported = HT_FREQUENCY_LIMIT_2600M;
1209         }
1210         /* unlikely cases, but include as a defensive measure, also avoid trick above */
1211         else if (nbCOF == 4)
1212         {
1213                 supported = HT_FREQUENCY_LIMIT_400M;
1214         }
1215         else if (nbCOF == 2)
1216         {
1217                 supported = HT_FREQUENCY_LIMIT_200M;
1218         }
1219         else
1220         {
1221                 STOP_HERE;
1222                 supported = HT_FREQUENCY_LIMIT_200M;
1223         }
1224
1225         return (fixEarlySampleFreqCapability(supported));
1226 }
1227
1228 /**----------------------------------------------------------------------------------------
1229  *
1230  * void
1231  * gatherLinkData(sMainData *pDat, cNorthBridge *nb)
1232  *
1233  *  Description:
1234  *       For all discovered links, populate the port list with the frequency and width
1235  *       capabilities.
1236  *
1237  *  Parameters:
1238  *      @param[in,out] sMainData*  pDat = our global state, port list
1239  *      @param[in]     cNorthBridge *nb = this northbridge
1240  *
1241  * ---------------------------------------------------------------------------------------
1242  */
1243 void gatherLinkData(sMainData *pDat, cNorthBridge *nb)
1244 {
1245         u8 i;
1246         SBDFO linkBase;
1247         u32 temp;
1248
1249         for (i = 0; i < pDat->TotalLinks*2; i++)
1250         {
1251                 if (pDat->PortList[i].Type == PORTLIST_TYPE_CPU)
1252                 {
1253                         linkBase = makeLinkBase(pDat->PortList[i].NodeID, pDat->PortList[i].Link);
1254
1255                         pDat->PortList[i].Pointer = linkBase;
1256
1257                         AmdPCIReadBits(linkBase + HTHOST_LINK_CONTROL_REG, 22, 20, &temp);
1258                         pDat->PortList[i].PrvWidthOutCap = convertBitsToWidth((u8)temp, pDat->nb);
1259
1260                         AmdPCIReadBits(linkBase + HTHOST_LINK_CONTROL_REG, 18, 16, &temp);
1261                         pDat->PortList[i].PrvWidthInCap = convertBitsToWidth((u8)temp, pDat->nb);
1262
1263                         AmdPCIReadBits(linkBase + HTHOST_FREQ_REV_REG, 31, 16, &temp);
1264                         pDat->PortList[i].PrvFrequencyCap = (u16)temp & 0x7FFF
1265                                  & nb->northBridgeFreqMask(pDat->PortList[i].NodeID, pDat->nb); // Mask off bit 15, reserved value
1266                 }
1267                 else
1268                 {
1269                         linkBase = pDat->PortList[i].Pointer;
1270                         if (pDat->PortList[i].Link == 1)
1271                          linkBase += HTSLAVE_LINK01_OFFSET;
1272
1273                         AmdPCIReadBits(linkBase + HTSLAVE_LINK_CONTROL_0_REG, 22, 20, &temp);
1274                         pDat->PortList[i].PrvWidthOutCap = convertBitsToWidth((u8)temp, pDat->nb);
1275
1276                         AmdPCIReadBits(linkBase + HTSLAVE_LINK_CONTROL_0_REG, 18, 16, &temp);
1277                         pDat->PortList[i].PrvWidthInCap = convertBitsToWidth((u8)temp, pDat->nb);
1278
1279                         AmdPCIReadBits(linkBase + HTSLAVE_FREQ_REV_0_REG, 31, 16, &temp);
1280                         pDat->PortList[i].PrvFrequencyCap = (u16)temp;
1281
1282                         if (pDat->HtBlock->AMD_CB_DeviceCapOverride)
1283                         {
1284                                 linkBase &= 0xFFFFF000;
1285                                 AmdPCIRead(linkBase, &temp);
1286
1287                                 pDat->HtBlock->AMD_CB_DeviceCapOverride(
1288                                         pDat->PortList[i].NodeID,
1289                                         pDat->PortList[i].HostLink,
1290                                         pDat->PortList[i].HostDepth,
1291                                         (u8)SBDFO_SEG(pDat->PortList[i].Pointer),
1292                                         (u8)SBDFO_BUS(pDat->PortList[i].Pointer),
1293                                         (u8)SBDFO_DEV(pDat->PortList[i].Pointer),
1294                                         temp,
1295                                         pDat->PortList[i].Link,
1296                                         &(pDat->PortList[i].PrvWidthInCap),
1297                                         &(pDat->PortList[i].PrvWidthOutCap),
1298                                         &(pDat->PortList[i].PrvFrequencyCap));
1299                         }
1300                 }
1301         }
1302 }
1303
1304 /**----------------------------------------------------------------------------------------
1305  *
1306  * void
1307  * setLinkData(sMainData *pDat, cNorthBridge *nb)
1308  *
1309  *  Description:
1310  *       Change the hardware state for all links according to the now optimized data in the
1311  *       port list data structure.
1312  *
1313  *  Parameters:
1314  *        @param[in]        sMainData*    pDat           = our global state, port list
1315  *        @param[in]        cNorthBridge *nb   = this northbridge
1316  *
1317  * ---------------------------------------------------------------------------------------
1318  */
1319 void setLinkData(sMainData *pDat, cNorthBridge *nb)
1320 {
1321         u8 i;
1322         SBDFO linkBase;
1323         u32 temp, widthin, widthout, bits;
1324
1325         for (i = 0; i < pDat->TotalLinks*2; i++)
1326         {
1327
1328                 ASSERT(pDat->PortList[i&0xFE].SelWidthOut == pDat->PortList[(i&0xFE)+1].SelWidthIn);
1329                 ASSERT(pDat->PortList[i&0xFE].SelWidthIn == pDat->PortList[(i&0xFE)+1].SelWidthOut);
1330                 ASSERT(pDat->PortList[i&0xFE].SelFrequency == pDat->PortList[(i&0xFE)+1].SelFrequency);
1331
1332                 if (pDat->PortList[i].SelRegang)
1333                 {
1334                         ASSERT(pDat->PortList[i].Type == PORTLIST_TYPE_CPU);
1335                         ASSERT(pDat->PortList[i].Link < 4);
1336                         temp = 1;
1337                         AmdPCIWriteBits(MAKE_SBDFO(makePCISegmentFromNode(pDat->PortList[i].NodeID),
1338                                         makePCIBusFromNode(pDat->PortList[i].NodeID),
1339                                         makePCIDeviceFromNode(pDat->PortList[i].NodeID),
1340                                         CPU_HTNB_FUNC_00,
1341                                         REG_HT_LINK_EXT_CONTROL0_0X170 + 4*pDat->PortList[i].Link),
1342                                         0, 0, &temp);
1343                 }
1344
1345                 if (pDat->PortList[i].Type == PORTLIST_TYPE_CPU)
1346                 {
1347                         if (pDat->HtBlock->AMD_CB_OverrideCpuPort)
1348                                 pDat->HtBlock->AMD_CB_OverrideCpuPort(pDat->PortList[i].NodeID,
1349                                                 pDat->PortList[i].Link,
1350                                                 &(pDat->PortList[i].SelWidthIn),
1351                                                 &(pDat->PortList[i].SelWidthOut),
1352                                                 &(pDat->PortList[i].SelFrequency));
1353                 }
1354                 else
1355                 {
1356                         if (pDat->HtBlock->AMD_CB_OverrideDevicePort)
1357                                 pDat->HtBlock->AMD_CB_OverrideDevicePort(pDat->PortList[i].NodeID,
1358                                                         pDat->PortList[i].HostLink,
1359                                                         pDat->PortList[i].HostDepth,
1360                                                         pDat->PortList[i].Link,
1361                                                         &(pDat->PortList[i].SelWidthIn),
1362                                                         &(pDat->PortList[i].SelWidthOut),
1363                                                         &(pDat->PortList[i].SelFrequency));
1364                 }
1365
1366                 linkBase = pDat->PortList[i].Pointer;
1367                 if ((pDat->PortList[i].Type == PORTLIST_TYPE_IO) && (pDat->PortList[i].Link == 1))
1368                         linkBase += HTSLAVE_LINK01_OFFSET;
1369
1370                 /* Some IO devices don't work properly when setting widths, so write them in a single operation,
1371                  * rather than individually.
1372                  */
1373                 widthout = convertWidthToBits(pDat->PortList[i].SelWidthOut, pDat->nb);
1374                 ASSERT(widthout == 1 || widthout == 0 || widthout == 5 || widthout == 4);
1375                 widthin = convertWidthToBits(pDat->PortList[i].SelWidthIn, pDat->nb);
1376                 ASSERT(widthin == 1 || widthin == 0 || widthin == 5 || widthin == 4);
1377
1378                 temp = (widthin & 7) | ((widthout & 7) << 4);
1379                 setHtControlRegisterBits(linkBase + HTHOST_LINK_CONTROL_REG, 31, 24, &temp);
1380
1381                 temp = pDat->PortList[i].SelFrequency;
1382                 if (pDat->PortList[i].Type == PORTLIST_TYPE_CPU)
1383                 {
1384                         ASSERT((temp >= HT_FREQUENCY_600M && temp <= HT_FREQUENCY_2600M)
1385                                 || (temp == HT_FREQUENCY_200M) || (temp == HT_FREQUENCY_400M));
1386                         AmdPCIWriteBits(linkBase + HTHOST_FREQ_REV_REG, 11, 8, &temp);
1387                         if (temp > HT_FREQUENCY_1000M) // Gen1 = 200Mhz -> 1000MHz, Gen3 = 1200MHz -> 2600MHz
1388                         {
1389                                 /* Enable  for Gen3 frequencies */
1390                                 temp = 1;
1391                         }
1392                         else
1393                         {
1394                                 /* Disable  for Gen1 frequencies */
1395                                 temp = 0;
1396                         }
1397                                 /* HT3 retry mode enable / disable */
1398                                 AmdPCIWriteBits(MAKE_SBDFO(makePCISegmentFromNode(pDat->PortList[i].NodeID),
1399                                                         makePCIBusFromNode(pDat->PortList[i].NodeID),
1400                                                         makePCIDeviceFromNode(pDat->PortList[i].NodeID),
1401                                                         CPU_HTNB_FUNC_00,
1402                                                         REG_HT_LINK_RETRY0_0X130 + 4*pDat->PortList[i].Link),
1403                                                         0, 0, &temp);
1404                                 /* and Scrambling enable / disable */
1405                                 AmdPCIWriteBits(MAKE_SBDFO(makePCISegmentFromNode(pDat->PortList[i].NodeID),
1406                                                 makePCIBusFromNode(pDat->PortList[i].NodeID),
1407                                                 makePCIDeviceFromNode(pDat->PortList[i].NodeID),
1408                                                 CPU_HTNB_FUNC_00,
1409                                                 REG_HT_LINK_EXT_CONTROL0_0X170 + 4*pDat->PortList[i].Link),
1410                                                 3, 3, &temp);
1411                 }
1412                 else
1413                 {
1414                         SBDFO currentPtr;
1415                         BOOL isFound;
1416
1417                         ASSERT(temp <= HT_FREQUENCY_2600M);
1418                         /* Write the frequency setting */
1419                         AmdPCIWriteBits(linkBase + HTSLAVE_FREQ_REV_0_REG, 11, 8, &temp);
1420
1421                         /* Handle additional HT3 frequency requirements, if needed,
1422                          * or clear them if switching down to ht1 on a warm reset.
1423                          * Gen1 = 200Mhz -> 1000MHz, Gen3 = 1200MHz -> 2600MHz
1424                          *
1425                          * Even though we assert if debugging, we need to check that the capability was found
1426                          * always, since this is an unknown hardware device, also we are taking
1427                          * unqualified frequency from the call backs
1428                          * (could be trying to do ht3 on an ht1 IO device).
1429                          */
1430
1431                         if (temp > HT_FREQUENCY_1000M)
1432                         {
1433                                 /* Enabling features if gen 3 */
1434                                 bits = 1;
1435                         }
1436                         else
1437                         {
1438                                 /* Disabling features if gen 1 */
1439                                 bits = 0;
1440                         }
1441
1442                         /* Retry Enable */
1443                         isFound = FALSE;
1444                         currentPtr = linkBase & (u32)0xFFFFF000; /* Set PCI Offset to 0 */
1445                         do
1446                         {
1447                                 AmdPCIFindNextCap(&currentPtr);
1448                                 if (currentPtr != ILLEGAL_SBDFO)
1449                                 {
1450                                         AmdPCIRead(currentPtr, &temp);
1451                                         /* HyperTransport Retry Capability? */
1452                                         if (IS_HT_RETRY_CAPABILITY(temp))
1453                                         {
1454                                                 ASSERT(pDat->PortList[i].Link < 2);
1455                                                 AmdPCIWriteBits(currentPtr + HTRETRY_CONTROL_REG,
1456                                                                 pDat->PortList[i].Link*16,
1457                                                                 pDat->PortList[i].Link*16,
1458                                                                 &bits);
1459                                                 isFound = TRUE;
1460                                         }
1461                                 /* Some other capability, keep looking */
1462                                 }
1463                                 else
1464                                 {
1465                                         /* If we are turning it off, that may mean the device was only ht1 capable,
1466                                          * so don't complain that we can't do it.
1467                                          */
1468                                         if (bits != 0)
1469                                         {
1470                                                 if (pDat->HtBlock->AMD_CB_EventNotify)
1471                                                 {
1472                                                         sHtEventOptRequiredCap evt ={sizeof(sHtEventOptRequiredCap),
1473                                                                                 pDat->PortList[i].NodeID,
1474                                                                                 pDat->PortList[i].HostLink,
1475                                                                                 pDat->PortList[i].HostDepth};
1476
1477                                                         pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_WARNING,
1478                                                                                 HT_EVENT_OPT_REQUIRED_CAP_RETRY,
1479                                                                                 (u8 *)&evt);
1480                                                 }
1481                                                 STOP_HERE;
1482                                         }
1483                                         isFound = TRUE;
1484                                 }
1485                         } while (!isFound);
1486
1487                         /* Scrambling enable */
1488                         isFound = FALSE;
1489                         currentPtr = linkBase & (u32)0xFFFFF000; /* Set PCI Offset to 0 */
1490                         do
1491                         {
1492                                 AmdPCIFindNextCap(&currentPtr);
1493                                 if (currentPtr != ILLEGAL_SBDFO)
1494                                 {
1495                                         AmdPCIRead(currentPtr, &temp);
1496                                         /* HyperTransport Gen3 Capability? */
1497                                         if (IS_HT_GEN3_CAPABILITY(temp))
1498                                         {
1499                                                 ASSERT(pDat->PortList[i].Link < 2);
1500                                                 AmdPCIWriteBits((currentPtr +
1501                                                         HTGEN3_LINK_TRAINING_0_REG +
1502                                                         pDat->PortList[i].Link*HTGEN3_LINK01_OFFSET),
1503                                                         3, 3, &bits);
1504                                                 isFound = TRUE;
1505                                         }
1506                                         /* Some other capability, keep looking */
1507                                         }
1508                                         else
1509                                         {
1510                                         /* If we are turning it off, that may mean the device was only ht1 capable,
1511                                          * so don't complain that we can't do it.
1512                                          */
1513                                         if (bits != 0)
1514                                         {
1515                                                 if (pDat->HtBlock->AMD_CB_EventNotify)
1516                                                 {
1517                                                         sHtEventOptRequiredCap evt ={sizeof(sHtEventOptRequiredCap),
1518                                                                         pDat->PortList[i].NodeID,
1519                                                                         pDat->PortList[i].HostLink,
1520                                                                         pDat->PortList[i].HostDepth};
1521
1522                                                         pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_WARNING,
1523                                                                                 HT_EVENT_OPT_REQUIRED_CAP_GEN3,
1524                                                                                 (u8 *)&evt);
1525                                                 }
1526                                                 STOP_HERE;
1527                                         }
1528                                         isFound = TRUE;
1529                                 }
1530                         } while (!isFound);
1531                 }
1532         }
1533 }
1534
1535 /**----------------------------------------------------------------------------------------
1536  *
1537  * void
1538  * fam0fWriteHTLinkCmdBufferAlloc(u8 node, u8 link, u8 req, u8 preq, u8 rsp, u8 prb)
1539  *
1540  *  Description:
1541  *      Set the command buffer allocations in the buffer count register for the node and link.
1542  *      The command buffer settings in the low 16 bits are the same on both
1543  *      family 10h and family 0fh northbridges.
1544  *
1545  *  Parameters:
1546  *      @param[in]  u8 node = The node to set allocations on
1547  *      @param[in]  u8 link = the link to set allocations on
1548  *      @param[in]  u8 req  = non-posted Request Command Buffers
1549  *      @param[in]  u8 preq = Posted Request Command Buffers
1550  *      @param[in]  u8 rsp  = Response Command Buffers
1551  *      @param[in]  u8 prb  = Probe Command Buffers
1552  *
1553  * ---------------------------------------------------------------------------------------
1554  */
1555 static void fam0fWriteHTLinkCmdBufferAlloc(u8 node, u8 link, u8 req, u8 preq, u8 rsp, u8 prb)
1556 {
1557         u32 temp;
1558         SBDFO currentPtr;
1559
1560         currentPtr = makeLinkBase(node, link);
1561         currentPtr += HTHOST_BUFFER_COUNT_REG;
1562
1563         /* non-posted Request Command Buffers */
1564         temp = req;
1565         AmdPCIWriteBits(currentPtr, 3, 0, &temp);
1566         /* Posted Request Command Buffers */
1567         temp = preq;
1568         AmdPCIWriteBits(currentPtr, 7, 4, &temp);
1569         /* Response Command Buffers */
1570         temp = rsp;
1571         AmdPCIWriteBits(currentPtr, 11, 8, &temp);
1572         /* Probe Command Buffers */
1573         temp = prb;
1574         AmdPCIWriteBits(currentPtr, 15, 12, &temp);
1575 }
1576
1577 /**----------------------------------------------------------------------------------------
1578  *
1579  * void
1580  * fam0fWriteHTLinkDatBufferAlloc(u8 node, u8 link, u8 reqD, u8 preqD, u8 rspD)
1581  *
1582  *  Description:
1583  *       Set the data buffer allocations in the buffer count register for the node and link.
1584  *       The command buffer settings in the high 16 bits are not the same on both
1585  *       family 10h and family 0fh northbridges.
1586  *
1587  *  Parameters:
1588  *      @param[in] u8 node  = The node to set allocations on
1589  *      @param[in] u8 link  = the link to set allocations on
1590  *      @param[in] u8 reqD  = non-posted Request Data Buffers
1591  *      @param[in] u8 preqD = Posted Request Data Buffers
1592  *      @param[in] u8 rspD  = Response Data Buffers
1593  *
1594  * ---------------------------------------------------------------------------------------
1595  */
1596 static void fam0fWriteHTLinkDatBufferAlloc(u8 node, u8 link, u8 reqD, u8 preqD, u8 rspD)
1597 {
1598         u32 temp;
1599         SBDFO currentPtr;
1600
1601         currentPtr = makeLinkBase(node, link);
1602         currentPtr += HTHOST_BUFFER_COUNT_REG;
1603
1604         /* Request Data Buffers */
1605         temp = reqD;
1606         AmdPCIWriteBits(currentPtr, 18, 16, &temp);
1607         /* Posted Request Data Buffers */
1608         temp = preqD;
1609         AmdPCIWriteBits(currentPtr, 22, 20, &temp);
1610         /* Response Data Buffers */
1611         temp = rspD;
1612         AmdPCIWriteBits(currentPtr, 26, 24, &temp);
1613 }
1614
1615 /**----------------------------------------------------------------------------------------
1616  *
1617  * void
1618  * ht3WriteTrafficDistribution(u32 links01, u32 links10, cNorthBridge *nb)
1619  *
1620  *  Description:
1621  *       Set the traffic distribution register for the links provided.
1622  *
1623  *  Parameters:
1624  *      @param[in] u32 links01   = coherent links from node 0 to 1
1625  *      @param[in] u32 links10   = coherent links from node 1 to 0
1626  *      @param[in] cNorthBridge* nb = this northbridge
1627  *
1628  * ---------------------------------------------------------------------------------------
1629  */
1630 void ht3WriteTrafficDistribution(u32 links01, u32 links10, cNorthBridge *nb)
1631 {
1632 #ifndef HT_BUILD_NC_ONLY
1633         u32 temp;
1634
1635         /* Node 0 */
1636         /* DstLnk */
1637         AmdPCIWriteBits(MAKE_SBDFO(makePCISegmentFromNode(0),
1638                         makePCIBusFromNode(0),
1639                         makePCIDeviceFromNode(0),
1640                         CPU_HTNB_FUNC_00,
1641                         REG_HT_TRAFFIC_DIST_0X164),
1642                         23, 16, &links01);
1643         /* DstNode = 1, cHTPrbDistEn=1, cHTRspDistEn=1, cHTReqDistEn=1 */
1644         temp = 0x0107;
1645         AmdPCIWriteBits(MAKE_SBDFO(makePCISegmentFromNode(0),
1646                         makePCIBusFromNode(0),
1647                         makePCIDeviceFromNode(0),
1648                         CPU_HTNB_FUNC_00,
1649                         REG_HT_TRAFFIC_DIST_0X164),
1650                         15, 0, &temp);
1651
1652         /* Node 1 */
1653         /* DstLnk */
1654         AmdPCIWriteBits(MAKE_SBDFO(makePCISegmentFromNode(1),
1655                         makePCIBusFromNode(1),
1656                         makePCIDeviceFromNode(1),
1657                         CPU_HTNB_FUNC_00,
1658                         REG_HT_TRAFFIC_DIST_0X164),
1659                         23, 16, &links10);
1660         /* DstNode = 0, cHTPrbDistEn=1, cHTRspDistEn=1, cHTReqDistEn=1 */
1661         temp = 0x0007;
1662         AmdPCIWriteBits(MAKE_SBDFO(makePCISegmentFromNode(1),
1663                         makePCIBusFromNode(1),
1664                         makePCIDeviceFromNode(1),
1665                         CPU_HTNB_FUNC_00,
1666                         REG_HT_TRAFFIC_DIST_0X164),
1667                         15, 0, &temp);
1668 #endif /* HT_BUILD_NC_ONLY */
1669 }
1670
1671 /**----------------------------------------------------------------------------------------
1672  *
1673  * void
1674  * ht1WriteTrafficDistribution(u32 links01, u32 links10, cNorthBridge *nb)
1675  *
1676  *  Description:
1677  *       Traffic distribution is more complex in this case as the routing table must be
1678  *       adjusted to use one link for requests and the other for responses.  Also,
1679  *       perform the buffer tunings on the links required for this config.
1680  *
1681  *  Parameters:
1682  *      @param[in]  u32  links01  = coherent links from node 0 to 1
1683  *      @param[in]  u32  links01  = coherent links from node 1 to 0
1684  *      @param[in]  cNorthBridge* nb = this northbridge
1685  *
1686  * ---------------------------------------------------------------------------------------
1687  */
1688 void ht1WriteTrafficDistribution(u32 links01, u32 links10, cNorthBridge *nb)
1689 {
1690 #ifndef HT_BUILD_NC_ONLY
1691         u32 route01, route10;
1692         u8 req0, req1, rsp0, rsp1, nclink;
1693
1694         /*
1695          * Get the current request route for 0->1 and 1->0.  This will indicate which of the links
1696          * in links01 are connected to which links in links10.  Since we have to route to distribute
1697          * traffic, we need to know that.       The link used by htinit will become the request, probe link.
1698          * the other link will be used for responses.
1699          */
1700
1701         /* Get the routes, and hang on to them, we will write them back updated. */
1702         AmdPCIRead(MAKE_SBDFO(makePCISegmentFromNode(0),
1703                                 makePCIBusFromNode(0),
1704                                 makePCIDeviceFromNode(0),
1705                                 CPU_HTNB_FUNC_00,
1706                                 REG_ROUTE1_0X44),
1707                                 &route01);
1708         AmdPCIRead(MAKE_SBDFO(makePCISegmentFromNode(1),
1709                                 makePCIBusFromNode(1),
1710                                 makePCIDeviceFromNode(1),
1711                                 CPU_HTNB_FUNC_00,
1712                                 REG_ROUTE0_0X40),
1713                                 &route10);
1714
1715         /* Convert the request routes to a link number.  Note "0xE" is ht1 nb specific.
1716          * Find the response link numbers.
1717         */
1718         ASSERT((route01 & 0xE) && (route10 & 0xE));    /* no route! error! */
1719         req0 = (u8)AmdBitScanReverse((route01 & 0xE)) - 1;
1720         req1 = (u8)AmdBitScanReverse((route10 & 0xE)) - 1;
1721         /* Now, find the other link for the responses */
1722         rsp0 = (u8)AmdBitScanReverse((links01 & ~((u32)1 << req0)));
1723         rsp1 = (u8)AmdBitScanReverse((links10 & ~((u32)1 << req1)));
1724
1725         /* ht1 nb restriction, must have exactly two links */
1726         ASSERT(((((links01 & ~((u32)1 << req0)) & ~((u32)1 << rsp0))) == 0)
1727                 && ((((links10 & ~((u32)1 << req1)) & ~((u32)1 << rsp1))) == 0));
1728
1729         route01 = (route01 & ~0x0E00) | ((u32)0x0100<<(rsp0 + 1));
1730         route10 = (route10 & ~0x0E00) | ((u32)0x0100<<(rsp1 + 1));
1731
1732         AmdPCIWrite(MAKE_SBDFO(makePCISegmentFromNode(0),
1733                                 makePCIBusFromNode(0),
1734                                 makePCIDeviceFromNode(0),
1735                                 CPU_HTNB_FUNC_00,
1736                                 REG_ROUTE1_0X44),
1737                                 &route01);
1738
1739         AmdPCIWrite(MAKE_SBDFO(makePCISegmentFromNode(1),
1740                                 makePCIBusFromNode(1),
1741                                 makePCIDeviceFromNode(1),
1742                                 CPU_HTNB_FUNC_00,
1743                                 REG_ROUTE0_0X40),
1744                                 &route10);
1745
1746         /* While we otherwise do buffer tunings elsewhere, for the dual cHT DP case with
1747          * ht1 northbridges like family 0Fh, do the tunings here where we have all the
1748          * link and route info at hand and don't need to recalculate it.
1749          */
1750
1751         /* Node 0, Request / Probe Link (note family F only has links < 4) */
1752         fam0fWriteHTLinkCmdBufferAlloc(0, req0, 6, 3, 1, 6);
1753         fam0fWriteHTLinkDatBufferAlloc(0, req0, 4, 3, 1);
1754         /* Node 0, Response Link (note family F only has links < 4) */
1755         fam0fWriteHTLinkCmdBufferAlloc(0, rsp0, 1, 0, 15, 0);
1756         fam0fWriteHTLinkDatBufferAlloc(0, rsp0, 1, 1, 6);
1757         /* Node 1, Request / Probe Link (note family F only has links < 4) */
1758         fam0fWriteHTLinkCmdBufferAlloc(1, req1, 6, 3, 1, 6);
1759         fam0fWriteHTLinkDatBufferAlloc(1, req1, 4, 3, 1);
1760         /* Node 1, Response Link (note family F only has links < 4) */
1761         fam0fWriteHTLinkCmdBufferAlloc(1, rsp1, 1, 0, 15, 0);
1762         fam0fWriteHTLinkDatBufferAlloc(1, rsp1, 1, 1, 6);
1763
1764         /* Node 0, is the third link non-coherent? */
1765         nclink = (u8)AmdBitScanReverse(((u8)0x07 & ~((u32)1 << req0) & ~((u32)1 << rsp0)));
1766         if (nb->verifyLinkIsNonCoherent(0, nclink, nb))
1767         {
1768                 fam0fWriteHTLinkCmdBufferAlloc(0, nclink, 6, 5, 2, 0);
1769         }
1770
1771         /* Node 1, is the third link non-coherent? */
1772         nclink = (u8)AmdBitScanReverse(((u8)0x07 & ~((u32)1 << req1) & ~((u32)1 << rsp1)));
1773         if (nb->verifyLinkIsNonCoherent(1, nclink, nb))
1774         {
1775                 fam0fWriteHTLinkCmdBufferAlloc(1, nclink, 6, 5, 2, 0);
1776         }
1777 #endif /* HT_BUILD_NC_ONLY */
1778 }
1779
1780 /**----------------------------------------------------------------------------------------
1781  *
1782  * void
1783  * fam0fBufferOptimizations(u8 node, sMainData *pDat, cNorthBridge *nb)
1784  *
1785  *  Description:
1786  *       Buffer tunings are inherently northbridge specific. Check for specific configs
1787  *       which require adjustments and apply any standard workarounds to this node.
1788  *
1789  *  Parameters:
1790  *      @param[in]  u8  node      = the node to
1791  *      @param[in]  sMainData *pDat  = coherent links from node 0 to 1
1792  *      @param[in]  cNorthBridge* nb = this northbridge
1793  *
1794  * ---------------------------------------------------------------------------------------
1795  */
1796 void fam0fBufferOptimizations(u8 node, sMainData *pDat, cNorthBridge *nb)
1797 {
1798 #ifndef HT_BUILD_NC_ONLY
1799         u8 i;
1800         u32 temp;
1801         SBDFO currentPtr;
1802
1803         ASSERT(node < nb->maxNodes);
1804
1805         /* Fix the FIFO pointer register before changing speeds */
1806         currentPtr = MAKE_SBDFO(makePCISegmentFromNode(node),
1807                                 makePCIBusFromNode(node),
1808                                 makePCIDeviceFromNode(node),
1809                                 CPU_NB_FUNC_03,
1810                                 REG_NB_FIFOPTR_3XDC);
1811         for (i=0; i < nb->maxLinks; i++)
1812         {
1813                 temp = 0;
1814                 if (nb->verifyLinkIsCoherent(node, i, nb))
1815                 {
1816                         temp = 0x26;
1817                         ASSERT(i<3);
1818                         AmdPCIWriteBits(currentPtr, 8*i + 5, 8*i, &temp);
1819                 }
1820                 else
1821                 {
1822                         if (nb->verifyLinkIsNonCoherent(node, i, nb))
1823                         {
1824                                 temp = 0x25;
1825                                 ASSERT(i<3);
1826                                 AmdPCIWriteBits(currentPtr, 8*i + 5, 8*i, &temp);
1827                         }
1828                 }
1829         }
1830         /*
1831          * 8P Buffer tuning.
1832          * Either apply the BKDG tunings or, if applicable, apply the more restrictive errata 153
1833          * workaround.
1834          * If 8 nodes, Check this node for 'inner' or 'outer'.
1835          * Tune each link based on coherent or non-coherent
1836          */
1837         if (pDat->NodesDiscovered >= 6)
1838         {
1839                 u8 j;
1840                 BOOL isOuter;
1841                 BOOL isErrata153;
1842
1843                 /* This is for family 0Fh, so assuming dual core max then 7 or 8 nodes are required
1844                  * to be in the situation of 14 or more cores.   We checked nodes above, cross check
1845                  * that the number of cores is 14 or more. We want both 14 cores with at least 7 or 8 nodes
1846                  * not one condition alone, to apply the errata 153 workaround.  Otherwise, 7 or 8 rev F
1847                  * nodes use the BKDG tuning.
1848                  */
1849
1850                 isErrata153 = 0;
1851
1852                 AmdPCIReadBits (MAKE_SBDFO(makePCISegmentFromNode(0),
1853                                         makePCIBusFromNode(0),
1854                                         makePCIDeviceFromNode(0),
1855                                         CPU_HTNB_FUNC_00,
1856                                         REG_NODE_ID_0X60),
1857                                         19, 16, &temp);
1858
1859                 if (temp >= 14)
1860                 {
1861                         /* Check whether we need to do errata 153 tuning or BKDG tuning.
1862                          * Errata 153 applies to JH-1, JH-2 and older.  It is fixed in JH-3
1863                          * (and, one assumes, from there on).
1864                          */
1865                         for (i=0; i < (pDat->NodesDiscovered +1); i++)
1866                         {
1867                                 AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(i),
1868                                                 makePCIBusFromNode(i),
1869                                                 makePCIDeviceFromNode(i),
1870                                                 CPU_NB_FUNC_03,
1871                                                 REG_NB_CPUID_3XFC),
1872                                                 7, 0, &temp);
1873                                 if (((u8)temp & ~0x40) < 0x13)
1874                                 {
1875                                         isErrata153 = 1;
1876                                         break;
1877                                 }
1878                         }
1879                 }
1880
1881                 for (i=0; i < CPU_ADDR_NUM_CONFIG_MAPS; i++)
1882                 {
1883                         isOuter = FALSE;
1884                         /* Check for outer node by scanning the config maps on node 0 for one
1885                          * which is assigned to this node.
1886                          */
1887                         currentPtr = MAKE_SBDFO(makePCISegmentFromNode(0),
1888                                                 makePCIBusFromNode(0),
1889                                                 makePCIDeviceFromNode(0),
1890                                                 CPU_ADDR_FUNC_01,
1891                                                 REG_ADDR_CONFIG_MAP0_1XE0 + (4 * i));
1892                         AmdPCIReadBits (currentPtr, 1, 0, &temp);
1893                         /* Make sure this config map is valid, if it is it will be enabled for read/write */
1894                         if (temp == 3)
1895                         {
1896                                 /* It's valid, get the node (that node is an outer node) */
1897                                 AmdPCIReadBits (currentPtr, 6, 4, &temp);
1898                                 /* Is the node we're working on now? */
1899                                 if (node == (u8)temp)
1900                                 {
1901                                         /* This is an outer node.       Tune it appropriately. */
1902                                         for (j=0; j < nb->maxLinks; j++)
1903                                         {
1904                                                 if (isErrata153)
1905                                                 {
1906                                                         if (nb->verifyLinkIsCoherent(node, j, nb))
1907                                                         {
1908                                                                 fam0fWriteHTLinkCmdBufferAlloc(node, j, 1, 1, 6, 4);
1909                                                         }
1910                                                         else
1911                                                         {
1912                                                                 if (nb->verifyLinkIsNonCoherent(node, j, nb))
1913                                                                 {
1914                                                                         fam0fWriteHTLinkCmdBufferAlloc(node, j, 5, 4, 1, 0);
1915                                                                 }
1916                                                         }
1917                                                 }
1918                                                 else
1919                                                 {
1920                                                         if (nb->verifyLinkIsCoherent(node, j, nb))
1921                                                         {
1922                                                                 fam0fWriteHTLinkCmdBufferAlloc(node, j, 1, 1, 8, 5);
1923                                                         }
1924                                                 }
1925                                         }
1926                                         /*
1927                                          * SRI to XBAR Buffer Counts are correct for outer node at power on defaults.
1928                                          */
1929                                         isOuter = TRUE;
1930                                         break;
1931                                 }
1932                         }
1933                         /* We fill config maps in ascending order, so if we didn't use this one, we're done. */
1934                         else break;
1935                 }
1936                 if (!isOuter)
1937                 {
1938                         if (isErrata153)
1939                         {
1940                                 /* Tuning for inner node coherent links */
1941                                 for (j=0; j < nb->maxLinks; j++)
1942                                 {
1943                                         if (nb->verifyLinkIsCoherent(node, j, nb))
1944                                         {
1945                                                 fam0fWriteHTLinkCmdBufferAlloc(node, j, 2, 1, 5, 4);
1946                                         }
1947
1948                                 }
1949                                 /* SRI to XBAR Buffer Count for inner nodes, zero DReq and DPReq */
1950                                 temp = 0;
1951                                 AmdPCIWriteBits (MAKE_SBDFO(makePCISegmentFromNode(node),
1952                                                         makePCIBusFromNode(node),
1953                                                         makePCIDeviceFromNode(node),
1954                                                         CPU_NB_FUNC_03,
1955                                                         REG_NB_SRI_XBAR_BUF_3X70),
1956                                                         31, 28, &temp);
1957                         }
1958                 }
1959
1960                 /*
1961                  * Tune MCT to XBAR Buffer Count the same an all nodes, 2 Probes, 5 Response
1962                  */
1963                 if (isErrata153)
1964                 {
1965                         temp = 0x25;
1966                         AmdPCIWriteBits (MAKE_SBDFO(makePCISegmentFromNode(node),
1967                                                 makePCIBusFromNode(node),
1968                                                 makePCIDeviceFromNode(node),
1969                                                 CPU_NB_FUNC_03,
1970                                                 REG_NB_MCT_XBAR_BUF_3X78),
1971                                                 14, 8, &temp);
1972                 }
1973         }
1974 #endif /* HT_BUILD_NC_ONLY */
1975 }
1976
1977 /**----------------------------------------------------------------------------------------
1978  *
1979  * void
1980  * fam10BufferOptimizations(u8 node, sMainData *pDat, cNorthBridge *nb)
1981  *
1982  *  Description:
1983  *       Buffer tunings are inherently northbridge specific. Check for specific configs
1984  *       which require adjustments and apply any standard workarounds to this node.
1985  *
1986  *  Parameters:
1987  *      @param[in] u8 node       = the node to tune
1988  *      @param[in] sMainData *pDat  = global state
1989  *      @param[in] cNorthBridge* nb = this northbridge
1990  *
1991  * ---------------------------------------------------------------------------------------
1992  */
1993 void fam10BufferOptimizations(u8 node, sMainData *pDat, cNorthBridge *nb)
1994 {
1995         u32 temp;
1996         SBDFO currentPtr;
1997         u8 i;
1998
1999         ASSERT(node < nb->maxNodes);
2000
2001         /*
2002          * Link to XCS Token Count Tuning
2003          *
2004          * For each active link that we reganged (so this unfortunately can't go into the PCI reg
2005          * table), we have to switch the Link to XCS Token Counts to the ganged state.
2006          * We do this here for the non-uma case, which is to write the values that would have
2007          * been power on defaults if the link was ganged at cold reset.
2008          */
2009         for (i = 0; i < pDat->TotalLinks*2; i++)
2010         {
2011                 if ((pDat->PortList[i].NodeID == node) && (pDat->PortList[i].Type == PORTLIST_TYPE_CPU))
2012                 {
2013                         /* If the link is greater than 4, this is a sublink 1, so it is not reganged. */
2014                         if (pDat->PortList[i].Link < 4)
2015                         {
2016                                 currentPtr = MAKE_SBDFO(makePCISegmentFromNode(node),
2017                                                 makePCIBusFromNode(node),
2018                                                 makePCIDeviceFromNode(node),
2019                                                 CPU_NB_FUNC_03,
2020                                                 REG_NB_LINK_XCS_TOKEN0_3X148 + 4*pDat->PortList[i].Link);
2021                                 if (pDat->PortList[i].SelRegang)
2022                                 {
2023                                         /* Handle all the regang Token count adjustments */
2024
2025                                         /* Sublink 0: [Probe0tok] = 2 [Rsp0tok] = 2 [PReq0tok] = 2 [Req0tok] = 2 */
2026                                         temp = 0xAA;
2027                                         AmdPCIWriteBits(currentPtr, 7, 0, &temp);
2028                                         /* Sublink 1: [Probe1tok] = 0 [Rsp1tok] = 0 [PReq1tok] = 0 [Req1tok] = 0 */
2029                                         temp = 0;
2030                                         AmdPCIWriteBits(currentPtr, 23, 16, &temp);
2031                                         /* [FreeTok] = 3 */
2032                                         temp = 3;
2033                                         AmdPCIWriteBits(currentPtr, 15, 14, &temp);
2034                                 }
2035                                 else
2036                                 {
2037                                         /* Read the regang bit in hardware */
2038                                         AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(pDat->PortList[i].NodeID),
2039                                                         makePCIBusFromNode(pDat->PortList[i].NodeID),
2040                                                         makePCIDeviceFromNode(pDat->PortList[i].NodeID),
2041                                                         CPU_HTNB_FUNC_00,
2042                                                         REG_HT_LINK_EXT_CONTROL0_0X170 + 4*pDat->PortList[i].Link),
2043                                                         0, 0, &temp);
2044                                         if (temp == 1)
2045                                         {
2046                                                 /* handle a minor adjustment for stapped ganged links.   If SelRegang is false we
2047                                                  * didn't do the regang, so if the bit is on then it's hardware strapped.
2048                                                  */
2049
2050                                                 /* [FreeTok] = 3 */
2051                                                 temp = 3;
2052                                                 AmdPCIWriteBits(currentPtr, 15, 14, &temp);
2053                                         }
2054                                 }
2055                         }
2056                 }
2057         }
2058 }
2059
2060 /*
2061  * North Bridge 'constructor'.
2062  *
2063  */
2064
2065 /**----------------------------------------------------------------------------------------
2066  *
2067  * void
2068  * newNorthBridge(u8 node, cNorthBridge *nb)
2069  *
2070  *  Description:
2071  *       Construct a new northbridge.  This routine encapsulates knowledge of how to tell
2072  *       significant differences between families of supported northbridges and what routines
2073  *       can be used in common and which are unique.  A fully populated northbridge interface
2074  *       is provided by nb.
2075  *
2076  *  Parameters:
2077  *        @param[in]        node          u8             = create a northbridge interface for this node.
2078  *        @param[out]       cNorthBridge* nb             = the caller's northbridge structure to initialize.
2079  *
2080  * ---------------------------------------------------------------------------------------
2081  */
2082 void newNorthBridge(u8 node, cNorthBridge *nb)
2083 {
2084         u32 match;
2085         u32 extFam, baseFam, model;
2086
2087         cNorthBridge fam10 =
2088         {
2089 #ifdef HT_BUILD_NC_ONLY
2090                 8,
2091                 1,
2092                 12,
2093 #else
2094                 8,
2095                 8,
2096                 64,
2097 #endif /* HT_BUILD_NC_ONLY*/
2098                 writeRoutingTable,
2099                 writeNodeID,
2100                 readDefLnk,
2101                 enableRoutingTables,
2102                 verifyLinkIsCoherent,
2103                 readTrueLinkFailStatus,
2104                 readToken,
2105                 writeToken,
2106                 fam10GetNumCoresOnNode,
2107                 setTotalNodesAndCores,
2108                 limitNodes,
2109                 writeFullRoutingTable,
2110                 isCompatible,
2111                 fam10IsCapable,
2112                 (void (*)(u8, u8, cNorthBridge*))commonVoid,
2113                 (BOOL (*)(u8, u8, sMainData*, cNorthBridge*))commonReturnFalse,
2114                 readSbLink,
2115                 verifyLinkIsNonCoherent,
2116                 ht3SetCFGAddrMap,
2117                 convertBitsToWidth,
2118                 convertWidthToBits,
2119                 fam10NorthBridgeFreqMask,
2120                 gatherLinkData,
2121                 setLinkData,
2122                 ht3WriteTrafficDistribution,
2123                 fam10BufferOptimizations,
2124                 0x00000001,
2125                 0x00000200,
2126                 18,
2127                 0x00000f01
2128         };
2129
2130         cNorthBridge fam0f =
2131         {
2132 #ifdef HT_BUILD_NC_ONLY
2133                 3,
2134                 1,
2135                 12,
2136 #else
2137                 3,
2138                 8,
2139                 32,
2140 #endif /* HT_BUILD_NC_ONLY*/
2141                 writeRoutingTable,
2142                 writeNodeID,
2143                 readDefLnk,
2144                 enableRoutingTables,
2145                 verifyLinkIsCoherent,
2146                 readTrueLinkFailStatus,
2147                 readToken,
2148                 writeToken,
2149                 fam0FGetNumCoresOnNode,
2150                 setTotalNodesAndCores,
2151                 limitNodes,
2152                 writeFullRoutingTable,
2153                 isCompatible,
2154                 fam0fIsCapable,
2155                 fam0fStopLink,
2156                 (BOOL (*)(u8, u8, sMainData*, cNorthBridge*))commonReturnFalse,
2157                 readSbLink,
2158                 verifyLinkIsNonCoherent,
2159                 ht1SetCFGAddrMap,
2160                 convertBitsToWidth,
2161                 convertWidthToBits,
2162                 ht1NorthBridgeFreqMask,
2163                 gatherLinkData,
2164                 setLinkData,
2165                 ht1WriteTrafficDistribution,
2166                 fam0fBufferOptimizations,
2167                 0x00000001,
2168                 0x00000100,
2169                 16,
2170                 0x00000f00
2171         };
2172
2173         /* Start with enough of the key to identify the northbridge interface */
2174         AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(node),
2175                         makePCIBusFromNode(node),
2176                         makePCIDeviceFromNode(node),
2177                         CPU_NB_FUNC_03,
2178                         REG_NB_CPUID_3XFC),
2179                         27, 20, &extFam);
2180         AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(node),
2181                         makePCIBusFromNode(node),
2182                         makePCIDeviceFromNode(node),
2183                         CPU_NB_FUNC_03,
2184                         REG_NB_CPUID_3XFC),
2185                         11, 8, &baseFam);
2186         AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(node),
2187                         makePCIBusFromNode(node),
2188                         makePCIDeviceFromNode(node),
2189                         CPU_NB_FUNC_03,
2190                         REG_NB_CPUID_3XFC),
2191                         7, 4, &model);
2192         match = (u32)((baseFam << 8) | extFam);
2193
2194         /* Test each in turn looking for a match.       Init the struct if found */
2195         if (match == fam10.compatibleKey)
2196         {
2197                 Amdmemcpy((void *)nb, (const void *)&fam10, (u32) sizeof(cNorthBridge));
2198         }
2199         else
2200         {
2201                 if (match == fam0f.compatibleKey)
2202                 {
2203                         Amdmemcpy((void *)nb, (const void *)&fam0f, (u32) sizeof(cNorthBridge));
2204                 }
2205                 else
2206                 {
2207                 STOP_HERE;
2208                 }
2209         }
2210
2211         /* Update the initial limited key to the real one, which may include other matching info */
2212         nb->compatibleKey = makeKey(node);
2213 }
2214