Add constants for fast path resume copying
[coreboot.git] / src / northbridge / amd / amdht / h3ncmn.c
1 /*
2  * This file is part of the coreboot 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  * static 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 static 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  * static 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 static 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  * static 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 static 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  * static 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 static 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  * static BOOL
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 static 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  * static 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 static 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;
405                                         evt.eSize = sizeof(sHtEventHWHtCrc);
406                                         evt.node = node;
407                                         evt.link = link;
408                                         evt.laneMask = (uint8)crc;
409
410                                         pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_HW_FAULT,
411                                                                         HT_EVENT_HW_HTCRC,
412                                                                         (u8 *)&evt);
413                                 }
414                         }
415                         else
416                         {
417                                 /* Some synch flood occurred */
418                                 if (pDat->HtBlock->AMD_CB_EventNotify)
419                                 {
420                                         /* Pass the node and link on which the generic synch flood event occurred. */
421                                         sHtEventHWSynchFlood evt;
422                                         evt.eSize = sizeof(sHtEventHWSynchFlood);
423                                         evt.node = node;
424                                         evt.link = link;
425
426                                         pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_HW_FAULT,
427                                                                         HT_EVENT_HW_SYNCHFLOOD,
428                                                                         (u8 *)&evt);
429                                 }
430                         }
431                 }
432         }
433         return ((after != 0) || unconnected);
434 }
435
436
437 /**----------------------------------------------------------------------------------------
438  *
439  * static u8
440  * readToken(u8 node, cNorthBridge *nb)
441  *
442  *  Description:
443  *      Read the token stored in the scratchpad register
444  *      NOTE: The location used to store the token is arbitrary.  The only
445  *      requirement is that the location warm resets to zero, and that
446  *      using it will have no ill-effects during HyperTransport initialization.
447  *
448  *  Parameters:
449  *      @param[in]  u8  node      = the node that will be examined
450  *      @param[in]  cNorthBridge *nb = this northbridge
451  *      @param[out] u8  result    = the Token read from the node
452  *
453  * ---------------------------------------------------------------------------------------
454  */
455 static u8 readToken(u8 node, cNorthBridge *nb)
456 {
457         u32 temp;
458
459         ASSERT((node < nb->maxNodes));
460         /* Use CpuCnt as a scratch register */
461         /* Limiting use to 4 bits makes code GH to rev F compatible. */
462         AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(node),
463                                 makePCIBusFromNode(node),
464                                 makePCIDeviceFromNode(node),
465                                 CPU_HTNB_FUNC_00,
466                                 REG_NODE_ID_0X60),
467                                 19, 16, &temp);
468
469         return (u8)temp;
470 }
471
472
473 /**----------------------------------------------------------------------------------------
474  *
475  * static void
476  * writeToken(u8 node, u8 Value, cNorthBridge *nb)
477  *
478  *  Description:
479  *      Write the token stored in the scratchpad register
480  *      NOTE: The location used to store the token is arbitrary.  The only
481  *      requirement is that the location warm resets to zero, and that
482  *      using it will have no ill-effects during HyperTransport initialization.
483  *      Limiting use to 4 bits makes code GH to rev F compatible.
484  *
485  *  Parameters:
486  *      @param[in]  u8  node  = the node that will be examined
487  *      @param[in]  cNorthBridge *nb  = this northbridge
488  *
489  * ---------------------------------------------------------------------------------------
490  */
491 static void writeToken(u8 node, u8 value, cNorthBridge *nb)
492 {
493         u32 temp = value;
494         ASSERT((node < nb->maxNodes));
495         /* Use CpuCnt as a scratch register */
496         /* Limiting use to 4 bits makes code GH to rev F compatible. */
497         AmdPCIWriteBits(MAKE_SBDFO(makePCISegmentFromNode(node),
498                                         makePCIBusFromNode(node),
499                                         makePCIDeviceFromNode(node),
500                                         CPU_HTNB_FUNC_00,
501                                         REG_NODE_ID_0X60),
502                                         19, 16, &temp);
503 }
504
505 /**----------------------------------------------------------------------------------------
506  *
507  * static u8
508  * fam0FGetNumCoresOnNode(u8 node, cNorthBridge *nb)
509  *
510  *  Description:
511  *      Return the number of cores (1 based count) on node.
512  *
513  *  Parameters:
514  *      @param[in]  u8  node      = the node that will be examined
515  *      @param[in]  cNorthBridge *nb = this northbridge
516  *      @param[out] u8  result    = the number of cores
517  *
518  * ---------------------------------------------------------------------------------------
519  */
520 static u8 fam0FGetNumCoresOnNode(u8 node, cNorthBridge *nb)
521 {
522         u32 temp;
523
524         ASSERT((node < nb->maxNodes));
525         /* Read CmpCap */
526         AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(node),
527                         makePCIBusFromNode(node),
528                         makePCIDeviceFromNode(node),
529                         CPU_NB_FUNC_03,
530                         REG_NB_CAPABILITY_3XE8),
531                         13, 12, &temp);
532
533         /* and add one */
534         return (u8)(temp+1);
535 }
536
537 /**----------------------------------------------------------------------------------------
538  *
539  * static u8
540  * fam10GetNumCoresOnNode(u8 node, cNorthBridge *nb)
541  *
542  *  Description:
543  *      Return the number of cores (1 based count) on node.
544  *
545  *  Parameters:
546  *      @param[in]  u8  node      = the node that will be examined
547  *      @param[in]  cNorthBridge *nb = this northbridge
548  *      @param[out] u8  result    = the number of cores
549  *
550  * ---------------------------------------------------------------------------------------
551  */
552 static u8 fam10GetNumCoresOnNode(u8 node, cNorthBridge *nb)
553 {
554         u32 temp, leveling, cores;
555         u8 i;
556
557         ASSERT((node < nb->maxNodes));
558         /* Read CmpCap [2][1:0] */
559         AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(node),
560                                 makePCIBusFromNode(node),
561                                 makePCIDeviceFromNode(node),
562                                 CPU_NB_FUNC_03,
563                                 REG_NB_CAPABILITY_3XE8),
564                                 15, 12, &temp);
565
566         /* bits[15,13,12] specify the cores */
567         /* Support Downcoring */
568         temp = ((temp & 8) >> 1) + (temp & 3);
569         cores = temp + 1;
570         AmdPCIReadBits (MAKE_SBDFO(makePCISegmentFromNode(node),
571                                         makePCIBusFromNode(node),
572                                         makePCIDeviceFromNode(node),
573                                         CPU_NB_FUNC_03,
574                                         REG_NB_DOWNCORE_3X190),
575                                         3, 0, &leveling);
576         for (i=0; i<cores; i++)
577         {
578                 if (leveling & ((u32) 1 << i))
579                 {
580                         temp--;
581                 }
582         }
583         return (u8)(temp+1);
584 }
585
586 /**----------------------------------------------------------------------------------------
587  *
588  * static void
589  * setTotalNodesAndCores(u8 node, u8 totalNodes, u8 totalCores, cNorthBridge *nb)
590  *
591  *  Description:
592  *      Write the total number of cores and nodes to the node
593  *
594  *  Parameters:
595  *      @param[in]  u8  node   = the node that will be examined
596  *      @param[in]  u8  totalNodes  = the total number of nodes
597  *      @param[in]  u8  totalCores  = the total number of cores
598  *      @param[in]  cNorthBridge *nb   = this northbridge
599  *
600  * ---------------------------------------------------------------------------------------
601  */
602 static void setTotalNodesAndCores(u8 node, u8 totalNodes, u8 totalCores, cNorthBridge *nb)
603 {
604         SBDFO nodeIDReg;
605         u32 temp;
606
607         ASSERT((node < nb->maxNodes) && (totalNodes <= nb->maxNodes));
608         nodeIDReg = MAKE_SBDFO(makePCISegmentFromNode(node),
609                                 makePCIBusFromNode(node),
610                                 makePCIDeviceFromNode(node),
611                                 CPU_HTNB_FUNC_00,
612                                 REG_NODE_ID_0X60);
613
614         temp = totalCores-1;
615         /* Rely on max number of nodes:cores for rev F and GH to make
616          * this code work, even though we write reserved bit 20 on rev F it will be
617          * zero in that case.
618          */
619         AmdPCIWriteBits(nodeIDReg, 20, 16, &temp);
620         temp = totalNodes-1;
621         AmdPCIWriteBits(nodeIDReg, 6,  4, &temp);
622 }
623
624 /**----------------------------------------------------------------------------------------
625  *
626  * static void
627  * limitNodes(u8 node, cNorthBridge *nb)
628  *
629  *  Description:
630  *      Limit coherent config accesses to cpus as indicated by nodecnt.
631  *
632  *  Parameters:
633  *      @param[in]  u8  node  = the node that will be examined
634  *      @param[in]  cNorthBridge *nb  = this northbridge
635  *
636  * ---------------------------------------------------------------------------------------
637  */
638 static void limitNodes(u8 node, cNorthBridge *nb)
639 {
640         u32 temp = 1;
641         ASSERT((node < nb->maxNodes));
642         AmdPCIWriteBits(MAKE_SBDFO(makePCISegmentFromNode(node),
643                                 makePCIBusFromNode(node),
644                                 makePCIDeviceFromNode(node),
645                                 CPU_HTNB_FUNC_00,
646                                 REG_LINK_TRANS_CONTROL_0X68),
647                                 15, 15, &temp);
648 }
649
650 /**----------------------------------------------------------------------------------------
651  *
652  * static void
653  * writeFullRoutingTable(u8 node, u8 target, u8 reqLink, u8 rspLink, u32 BClinks, cNorthBridge *nb)
654  *
655  *  Description:
656  *      Write the routing table entry for node to target, using the request link, response
657  *      link, and broadcast links provided.
658  *
659  *  Parameters:
660  *      @param[in]  u8  node   = the node that will be examined
661  *      @param[in]  u8  target   = the target node for these routes
662  *      @param[in]  u8  reqLink  = the link for requests to target
663  *      @param[in]  u8  rspLink  = the link for responses to target
664  *      @param[in]  u32 bClinks  = the broadcast links
665  *      @param[in]  cNorthBridge *nb  = this northbridge
666  *
667  * ---------------------------------------------------------------------------------------
668  */
669 static void writeFullRoutingTable(u8 node, u8 target, u8 reqLink, u8 rspLink, u32 bClinks, cNorthBridge *nb)
670 {
671 #ifndef HT_BUILD_NC_ONLY
672         u32 value = 0;
673
674         ASSERT((node < nb->maxNodes) && (target < nb->maxNodes));
675         if (reqLink == ROUTETOSELF)
676                 value |= nb->selfRouteRequestMask;
677         else
678                 value |= nb->selfRouteRequestMask << (reqLink+1);
679
680         if (rspLink == ROUTETOSELF)
681                 value |= nb->selfRouteResponseMask;
682         else
683                 value |= nb->selfRouteResponseMask << (rspLink+1);
684
685         /* Allow us to accept a Broadcast ourselves, then set broadcasts for routes */
686         value |= (u32)1 << nb->broadcastSelfBit;
687         value |= (u32)bClinks << (nb->broadcastSelfBit + 1);
688
689         AmdPCIWrite(MAKE_SBDFO(makePCISegmentFromNode(node),
690                                 makePCIBusFromNode(node),
691                                 makePCIDeviceFromNode(node),
692                                 CPU_HTNB_FUNC_00,
693                                 REG_ROUTE0_0X40 + target*4), &value);
694 #else
695         STOP_HERE;
696 #endif /* HT_BUILD_NC_ONLY */
697 }
698
699 /**----------------------------------------------------------------------------------------
700  *
701  * static u32
702  * makeKey(u8 currentNode)
703  *
704  *  Description:
705  *      Private routine to northbridge code.
706  *      Determine whether a node is compatible with the discovered configuration so
707  *      far.  Currently, that means the family, extended family of the new node are the
708  *      same as the BSP's.
709  *
710  *  Parameters:
711  *      @param[in]  u8   node   = the node
712  *      @param[out] u32  result = the key value
713  *
714  * ---------------------------------------------------------------------------------------
715  */
716 static u32 makeKey(u8 node)
717 {
718         u32 extFam, baseFam;
719         AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(node),
720                                 makePCIBusFromNode(node),
721                                 makePCIDeviceFromNode(node),
722                                 CPU_NB_FUNC_03,
723                                 REG_NB_CPUID_3XFC),
724                                 27, 20, &extFam);
725         AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(node),
726                                 makePCIBusFromNode(node),
727                                 makePCIDeviceFromNode(node),
728                                 CPU_NB_FUNC_03,
729                                 REG_NB_CPUID_3XFC),
730                                 11, 8, &baseFam);
731         return ((u32)(baseFam << 8) | extFam);
732 }
733
734
735 /**----------------------------------------------------------------------------------------
736  *
737  * static BOOL
738  * isCompatible(u8 currentNode, cNorthBridge *nb)
739  *
740  *  Description:
741  *      Determine whether a node is compatible with the discovered configuration so
742  *      far.  Currently, that means the family, extended family of the new node are the
743  *      same as the BSP's.
744  *
745  *  Parameters:
746  *      @param[in]  u8  node   = the node
747  *      @param[in]  cNorthBridge *nb  = this northbridge
748  *      @param[out] BOOL   result = true: the new is compatible, false: it is not
749  *
750  * ---------------------------------------------------------------------------------------
751  */
752 static BOOL isCompatible(u8 node, cNorthBridge *nb)
753 {
754         return (makeKey(node) == nb->compatibleKey);
755 }
756
757 /**----------------------------------------------------------------------------------------
758  *
759  * static BOOL
760  * fam0fIsCapable(u8 node, sMainData *pDat, cNorthBridge *nb)
761  *
762  *  Description:
763  *      Get node capability and update the minimum supported system capability.
764  *      Return whether the current configuration exceeds the capability.
765  *
766  *  Parameters:
767  *      @param[in] u8  node      = the node
768  *      @param[in,out]  sMainData *pDat = sysMpCap (updated) and NodesDiscovered
769  *      @param[in] cNorthBridge *nb = this northbridge
770  *      @param[out] BOOL  result    = true: system is capable of current config.
771  *                            false: system is not capable of current config.
772  *
773  * ---------------------------------------------------------------------------------------
774  */
775 static BOOL fam0fIsCapable(u8 node, sMainData *pDat, cNorthBridge *nb)
776 {
777 #ifndef HT_BUILD_NC_ONLY
778         u32 temp;
779         u8 maxNodes;
780
781         ASSERT(node < nb->maxNodes);
782
783         AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(node),
784                                 makePCIBusFromNode(node),
785                                 makePCIDeviceFromNode(node),
786                                 CPU_NB_FUNC_03,
787                                 REG_NB_CAPABILITY_3XE8),
788                                 2, 1, &temp);
789         if (temp > 1)
790         {
791                 maxNodes = 8;
792         } else {
793                 if (temp == 1)
794                 {
795                         maxNodes = 2;
796                 } else {
797                         maxNodes = 1;
798                 }
799         }
800         if (pDat->sysMpCap > maxNodes)
801         {
802                  pDat->sysMpCap = maxNodes;
803         }
804         /* Note since sysMpCap is one based and NodesDiscovered is zero based, equal is false */
805         return (pDat->sysMpCap > pDat->NodesDiscovered);
806 #else
807         return 1;
808 #endif
809 }
810
811 /**----------------------------------------------------------------------------------------
812  *
813  * static BOOL
814  * fam10IsCapable(u8 node, sMainData *pDat, cNorthBridge *nb)
815  *
816  *  Description:
817  *      Get node capability and update the minimum supported system capability.
818  *      Return whether the current configuration exceeds the capability.
819  *
820  *  Parameters:
821  *      @param[in] u8  node   = the node
822  *      @param[in,out] sMainData *pDat = sysMpCap (updated) and NodesDiscovered
823  *      @param[in]  cNorthBridge *nb   = this northbridge
824  *      @param[out] BOOL  result = true: system is capable of current config.
825  *                         false: system is not capable of current config.
826  *
827  * ---------------------------------------------------------------------------------------
828  */
829 static BOOL fam10IsCapable(u8 node, sMainData *pDat, cNorthBridge *nb)
830 {
831 #ifndef HT_BUILD_NC_ONLY
832         u32 temp;
833         u8 maxNodes;
834
835         ASSERT(node < nb->maxNodes);
836
837         AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(node),
838                                 makePCIBusFromNode(node),
839                                 makePCIDeviceFromNode(node),
840                                 CPU_NB_FUNC_03,
841                                 REG_NB_CAPABILITY_3XE8),
842                                 18, 16, &temp);
843
844         if (temp != 0)
845         {
846                 maxNodes = (1 << (~temp & 0x3));  /* That is, 1, 2, 4, or 8 */
847         }
848         else
849         {
850                 maxNodes = 8;
851         }
852
853         if (pDat->sysMpCap > maxNodes)
854         {
855                 pDat->sysMpCap = maxNodes;
856         }
857         /* Note since sysMpCap is one based and NodesDiscovered is zero based, equal is false */
858         return (pDat->sysMpCap > pDat->NodesDiscovered);
859 #else
860         return 1;
861 #endif
862 }
863
864 /**----------------------------------------------------------------------------------------
865  *
866  * static void
867  * fam0fStopLink(u8 currentNode, u8 currentLink, cNorthBridge *nb)
868  *
869  *  Description:
870  *      Disable a cHT link on node by setting F0x[E4, C4, A4, 84][TransOff, EndOfChain]=1
871  *
872  *  Parameters:
873  *      @param[in]  u8  node      = the node this link is on
874  *      @param[in]  u8  link      = the link to stop
875  *      @param[in]  cNorthBridge *nb = this northbridge
876  *
877  * ---------------------------------------------------------------------------------------
878  */
879 static void fam0fStopLink(u8 node, u8 link, cNorthBridge *nb)
880 {
881 #ifndef HT_BUILD_NC_ONLY
882         u32 temp;
883         SBDFO linkBase;
884
885         ASSERT((node < nb->maxNodes) && (link < nb->maxLinks));
886
887         linkBase = makeLinkBase(node, link);
888
889         /* Set TransOff, EndOfChain */
890         temp = 3;
891         setHtControlRegisterBits(linkBase + HTHOST_LINK_CONTROL_REG, 7, 6, &temp);
892 #endif
893 }
894
895 /**----------------------------------------------------------------------------------------
896  *
897  * static void
898  * commonVoid()
899  *
900  *  Description:
901  *      Nothing.
902  *
903  *  Parameters:
904  *              None.
905  *
906  * ---------------------------------------------------------------------------------------
907  */
908 static void commonVoid(void)
909 {
910 }
911
912 /**----------------------------------------------------------------------------------------
913  *
914  * static BOOL
915  * commonReturnFalse()
916  *
917  *  Description:
918  *      Return False.
919  *
920  *  Parameters:
921  *           @param[out]    BOOL     result        = false
922  * ---------------------------------------------------------------------------------------
923  */
924 static BOOL commonReturnFalse(void)
925 {
926         return 0;
927 }
928
929 /***************************************************************************
930  ***                    Non-coherent init code                            ***
931  ***                    Northbridge access routines                       ***
932  ***************************************************************************/
933
934 /**----------------------------------------------------------------------------------------
935  *
936  * static u8
937  * readSbLink(cNorthBridge *nb)
938  *
939  *  Description:
940  *       Return the link to the Southbridge
941  *
942  *  Parameters:
943  *      @param[in]  cNorthBridge *nb = this northbridge
944  *      @param[out] u8    results = the link to the southbridge
945  *
946  * ---------------------------------------------------------------------------------------
947  */
948 static u8 readSbLink(cNorthBridge *nb)
949 {
950         u32 temp;
951         AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(0),
952                                 makePCIBusFromNode(0),
953                                 makePCIDeviceFromNode(0),
954                                 CPU_HTNB_FUNC_00,
955                                 REG_UNIT_ID_0X64),
956                                 10, 8, &temp);
957         return (u8)temp;
958 }
959
960 /**----------------------------------------------------------------------------------------
961  *
962  * static BOOL
963  * verifyLinkIsNonCoherent(u8 node, u8 link, cNorthBridge *nb)
964  *
965  *  Description:
966  *       Verify that the link is non-coherent, connected, and ready
967  *
968  *  Parameters:
969  *      @param[in]  u8  node   = the node that will be examined
970  *      @param[in]  u8  link   = the Link on that node to examine
971  *      @param[in]  cNorthBridge *nb = this northbridge
972  *      @param[out] u8  results   = true - The link has the following status
973  *                                      LinkCon=1,     Link is connected
974  *                                      InitComplete=1,Link initilization is complete
975  *                                      NC=1,          Link is coherent
976  *                                      UniP-cLDT=0,   Link is not Uniprocessor cLDT
977  *                                      LinkConPend=0  Link connection is not pending
978  *                                      false- The link has some other status
979  *
980  * ---------------------------------------------------------------------------------------
981  */
982 static BOOL verifyLinkIsNonCoherent(u8 node, u8 link, cNorthBridge *nb)
983 {
984         u32 linkType;
985         SBDFO linkBase;
986
987         ASSERT((node < nb->maxNodes) && (link < nb->maxLinks));
988
989         linkBase = makeLinkBase(node, link);
990
991         /* FN0_98/A4/C4 = LDT Type Register */
992         AmdPCIRead(linkBase + HTHOST_LINK_TYPE_REG, &linkType);
993
994         /* Verify linkCon=1, InitComplete=1, NC=0, UniP-cLDT=0, LinkConPend=0 */
995         return (linkType & HTHOST_TYPE_MASK) ==  HTHOST_TYPE_NONCOHERENT;
996 }
997
998 /**----------------------------------------------------------------------------------------
999  *
1000  * static void
1001  * ht3SetCFGAddrMap(u8 cfgMapIndex, u8 secBus, u8 subBus, u8 targetNode, u8 targetLink, sMainData *pDat, cNorthBridge *nb)
1002  *
1003  *  Description:
1004  *       Configure and enable config access to a non-coherent chain for the given bus range.
1005  *
1006  *  Parameters:
1007  *      @param[in] u8 cfgRouteIndex = the map entry to set
1008  *      @param[in] u8 secBus      = The secondary bus number to use
1009  *      @param[in] u8 subBus      = The subordinate bus number to use
1010  *      @param[in] u8 targetNode  = The node  that shall be the recipient of the traffic
1011  *      @param[in] u8 targetLink  = The link that shall be the recipient of the traffic
1012  *      @param[in] sMainData* pDat   = our global state
1013  *      @param[in] cNorthBridge *nb  = this northbridge
1014  *
1015  * ---------------------------------------------------------------------------------------
1016  */
1017 static void  ht3SetCFGAddrMap(u8 cfgMapIndex, u8 secBus, u8 subBus, u8 targetNode, u8 targetLink, sMainData *pDat, cNorthBridge *nb)
1018 {
1019         u8 curNode;
1020         SBDFO linkBase;
1021         u32 temp;
1022
1023         linkBase = makeLinkBase(targetNode, targetLink);
1024
1025         ASSERT(secBus <= subBus);
1026         temp = secBus;
1027         AmdPCIWriteBits(linkBase + HTHOST_ISOC_REG, 15, 8, &temp);
1028
1029         /* For target link, note that rev F uses bits 9:8 and only with GH is bit 10
1030          * set to indicate a sublink.  For node, we are currently not supporting Extended
1031          * routing tables.
1032          */
1033         temp = ((u32)subBus << 24) + ((u32)secBus << 16) + ((u32)targetLink << 8)
1034                 + ((u32)targetNode << 4) + (u32)3;
1035         for (curNode = 0; curNode < pDat->NodesDiscovered+1; curNode++)
1036                 AmdPCIWrite(MAKE_SBDFO(makePCISegmentFromNode(curNode),
1037                                         makePCIBusFromNode(curNode),
1038                                         makePCIDeviceFromNode(curNode),
1039                                         CPU_ADDR_FUNC_01,
1040                                         REG_ADDR_CONFIG_MAP0_1XE0 + 4*cfgMapIndex),
1041                                         &temp);
1042 }
1043
1044 /**----------------------------------------------------------------------------------------
1045  *
1046  * static void
1047  * ht1SetCFGAddrMap(u8 cfgMapIndex, u8 secBus, u8 subBus, u8 targetNode, u8 targetLink, sMainData *pDat, cNorthBridge *nb)
1048  *
1049  *  Description:
1050  *       Configure and enable config access to a non-coherent chain for the given bus range.
1051  *
1052  *  Parameters:
1053  *      @param[in] u8  cfgMapIndex = the map entry to set
1054  *      @param[in] u8  secBus      = The secondary bus number to use
1055  *      @param[in] u8  subBus      = The subordinate bus number to use
1056  *      @param[in] u8  targetNode  = The node  that shall be the recipient of the traffic
1057  *      @param[in] u8  targetLink  = The link that shall be the recipient of the traffic
1058  *      @param[in] sMainData*  pDat   = our global state
1059  *      @param[in] cNorthBridge *nb   = this northbridge
1060  *
1061  * ---------------------------------------------------------------------------------------
1062  */
1063 static void ht1SetCFGAddrMap(u8 cfgMapIndex, u8 secBus, u8 subBus, u8 targetNode, u8 targetLink, sMainData *pDat, cNorthBridge *nb)
1064 {
1065         u8 curNode;
1066         SBDFO linkBase;
1067         u32 temp;
1068
1069         linkBase = makeLinkBase(targetNode, targetLink);
1070
1071         ASSERT(secBus <= subBus);
1072         temp = secBus;
1073         AmdPCIWriteBits(linkBase + HTHOST_ISOC_REG, 15, 8, &temp);
1074
1075         temp = subBus;
1076         AmdPCIWriteBits(linkBase + HTHOST_ISOC_REG, 23, 16, &temp);
1077
1078         /* For target link, note that rev F uses bits 9:8 and only with GH is bit 10
1079          * set to indicate a sublink.  For node, we are currently not supporting Extended
1080          * routing tables.
1081          */
1082         temp = ((u32)subBus << 24) + ((u32)secBus << 16) + ((u32)targetLink << 8)
1083                 + ((u32)targetNode << 4) + (u32)3;
1084         for (curNode = 0; curNode < pDat->NodesDiscovered+1; curNode++)
1085                  AmdPCIWrite(MAKE_SBDFO(makePCISegmentFromNode(curNode),
1086                                         makePCIBusFromNode(curNode),
1087                                         makePCIDeviceFromNode(curNode),
1088                                         CPU_ADDR_FUNC_01,
1089                                         REG_ADDR_CONFIG_MAP0_1XE0 + 4*cfgMapIndex),
1090                                         &temp);
1091 }
1092
1093 /***************************************************************************
1094  ***                             Link Optimization                        ***
1095  ***************************************************************************/
1096
1097 /**----------------------------------------------------------------------------------------
1098  *
1099  * static u8
1100  * convertBitsToWidth(u8 value, cNorthBridge *nb)
1101  *
1102  *  Description:
1103  *       Given the bits set in the register field, return the width it represents
1104  *
1105  *  Parameters:
1106  *      @param[in]  u8  value   = The bits for the register
1107  *      @param[in]  cNorthBridge *nb = this northbridge
1108  *      @param[out] u8  results = The width
1109  *
1110  * ---------------------------------------------------------------------------------------
1111  */
1112 static u8 convertBitsToWidth(u8 value, cNorthBridge *nb)
1113 {
1114         switch(value) {
1115         case 1: return 16;
1116         case 0: return 8;
1117         case 5: return 4;
1118         case 4: return 2;
1119         default: STOP_HERE; /*  This is an error internal condition */
1120         }
1121         return 0; // shut up GCC.
1122 }
1123
1124 /**----------------------------------------------------------------------------------------
1125  *
1126  * static u8
1127  * convertWidthToBits(u8 value, cNorthBridge *nb)
1128  *
1129  *  Description:
1130  *      Translate a desired width setting to the bits to set in the register field
1131  *
1132  *  Parameters:
1133  *      @param[in]  u8  value     = The width
1134  *      @param[in]  cNorthBridge *nb = this northbridge
1135  *      @param[out] u8  results   = The bits for the register
1136  *
1137  * ---------------------------------------------------------------------------------------
1138  */
1139 static u8 convertWidthToBits(u8 value, cNorthBridge *nb)
1140 {
1141         switch (value) {
1142         case 16: return 1;
1143         case  8: return 0;
1144         case  4: return 5;
1145         case  2: return 4;
1146         default: STOP_HERE; /*  This is an internal error condition */
1147         }
1148         return 0; // shut up GCC
1149 }
1150
1151 /**----------------------------------------------------------------------------------------
1152  *
1153  * static 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 static 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  * static 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 static 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  * static 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 static 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  * static 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 static 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;
1473                                                         evt.eSize = sizeof(sHtEventOptRequiredCap);
1474                                                         evt.node = pDat->PortList[i].NodeID;
1475                                                         evt.link = pDat->PortList[i].HostLink;
1476                                                         evt.depth = pDat->PortList[i].HostDepth;
1477
1478                                                         pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_WARNING,
1479                                                                                 HT_EVENT_OPT_REQUIRED_CAP_RETRY,
1480                                                                                 (u8 *)&evt);
1481                                                 }
1482                                                 STOP_HERE;
1483                                         }
1484                                         isFound = TRUE;
1485                                 }
1486                         } while (!isFound);
1487
1488                         /* Scrambling enable */
1489                         isFound = FALSE;
1490                         currentPtr = linkBase & (u32)0xFFFFF000; /* Set PCI Offset to 0 */
1491                         do
1492                         {
1493                                 AmdPCIFindNextCap(&currentPtr);
1494                                 if (currentPtr != ILLEGAL_SBDFO)
1495                                 {
1496                                         AmdPCIRead(currentPtr, &temp);
1497                                         /* HyperTransport Gen3 Capability? */
1498                                         if (IS_HT_GEN3_CAPABILITY(temp))
1499                                         {
1500                                                 ASSERT(pDat->PortList[i].Link < 2);
1501                                                 AmdPCIWriteBits((currentPtr +
1502                                                         HTGEN3_LINK_TRAINING_0_REG +
1503                                                         pDat->PortList[i].Link*HTGEN3_LINK01_OFFSET),
1504                                                         3, 3, &bits);
1505                                                 isFound = TRUE;
1506                                         }
1507                                         /* Some other capability, keep looking */
1508                                         }
1509                                         else
1510                                         {
1511                                         /* If we are turning it off, that may mean the device was only ht1 capable,
1512                                          * so don't complain that we can't do it.
1513                                          */
1514                                         if (bits != 0)
1515                                         {
1516                                                 if (pDat->HtBlock->AMD_CB_EventNotify)
1517                                                 {
1518                                                         sHtEventOptRequiredCap evt;
1519                                                         evt.eSize = sizeof(sHtEventOptRequiredCap);
1520                                                         evt.node = pDat->PortList[i].NodeID;
1521                                                         evt.link = pDat->PortList[i].HostLink;
1522                                                         evt.depth = pDat->PortList[i].HostDepth;
1523
1524                                                         pDat->HtBlock->AMD_CB_EventNotify(HT_EVENT_CLASS_WARNING,
1525                                                                                 HT_EVENT_OPT_REQUIRED_CAP_GEN3,
1526                                                                                 (u8 *)&evt);
1527                                                 }
1528                                                 STOP_HERE;
1529                                         }
1530                                         isFound = TRUE;
1531                                 }
1532                         } while (!isFound);
1533                 }
1534         }
1535 }
1536
1537 /**----------------------------------------------------------------------------------------
1538  *
1539  * void
1540  * fam0fWriteHTLinkCmdBufferAlloc(u8 node, u8 link, u8 req, u8 preq, u8 rsp, u8 prb)
1541  *
1542  *  Description:
1543  *      Set the command buffer allocations in the buffer count register for the node and link.
1544  *      The command buffer settings in the low 16 bits are the same on both
1545  *      family 10h and family 0fh northbridges.
1546  *
1547  *  Parameters:
1548  *      @param[in]  u8 node = The node to set allocations on
1549  *      @param[in]  u8 link = the link to set allocations on
1550  *      @param[in]  u8 req  = non-posted Request Command Buffers
1551  *      @param[in]  u8 preq = Posted Request Command Buffers
1552  *      @param[in]  u8 rsp  = Response Command Buffers
1553  *      @param[in]  u8 prb  = Probe Command Buffers
1554  *
1555  * ---------------------------------------------------------------------------------------
1556  */
1557 #ifndef HT_BUILD_NC_ONLY
1558
1559 static void fam0fWriteHTLinkCmdBufferAlloc(u8 node, u8 link, u8 req, u8 preq, u8 rsp, u8 prb)
1560 {
1561         u32 temp;
1562         SBDFO currentPtr;
1563
1564         currentPtr = makeLinkBase(node, link);
1565         currentPtr += HTHOST_BUFFER_COUNT_REG;
1566
1567         /* non-posted Request Command Buffers */
1568         temp = req;
1569         AmdPCIWriteBits(currentPtr, 3, 0, &temp);
1570         /* Posted Request Command Buffers */
1571         temp = preq;
1572         AmdPCIWriteBits(currentPtr, 7, 4, &temp);
1573         /* Response Command Buffers */
1574         temp = rsp;
1575         AmdPCIWriteBits(currentPtr, 11, 8, &temp);
1576         /* Probe Command Buffers */
1577         temp = prb;
1578         AmdPCIWriteBits(currentPtr, 15, 12, &temp);
1579 }
1580 #endif /* HT_BUILD_NC_ONLY */
1581
1582 /**----------------------------------------------------------------------------------------
1583  *
1584  * void
1585  * fam0fWriteHTLinkDatBufferAlloc(u8 node, u8 link, u8 reqD, u8 preqD, u8 rspD)
1586  *
1587  *  Description:
1588  *       Set the data buffer allocations in the buffer count register for the node and link.
1589  *       The command buffer settings in the high 16 bits are not the same on both
1590  *       family 10h and family 0fh northbridges.
1591  *
1592  *  Parameters:
1593  *      @param[in] u8 node  = The node to set allocations on
1594  *      @param[in] u8 link  = the link to set allocations on
1595  *      @param[in] u8 reqD  = non-posted Request Data Buffers
1596  *      @param[in] u8 preqD = Posted Request Data Buffers
1597  *      @param[in] u8 rspD  = Response Data Buffers
1598  *
1599  * ---------------------------------------------------------------------------------------
1600  */
1601 #ifndef HT_BUILD_NC_ONLY
1602
1603 static void fam0fWriteHTLinkDatBufferAlloc(u8 node, u8 link, u8 reqD, u8 preqD, u8 rspD)
1604 {
1605         u32 temp;
1606         SBDFO currentPtr;
1607
1608         currentPtr = makeLinkBase(node, link);
1609         currentPtr += HTHOST_BUFFER_COUNT_REG;
1610
1611         /* Request Data Buffers */
1612         temp = reqD;
1613         AmdPCIWriteBits(currentPtr, 18, 16, &temp);
1614         /* Posted Request Data Buffers */
1615         temp = preqD;
1616         AmdPCIWriteBits(currentPtr, 22, 20, &temp);
1617         /* Response Data Buffers */
1618         temp = rspD;
1619         AmdPCIWriteBits(currentPtr, 26, 24, &temp);
1620 }
1621 #endif /* HT_BUILD_NC_ONLY */
1622
1623 /**----------------------------------------------------------------------------------------
1624  *
1625  * static void
1626  * ht3WriteTrafficDistribution(u32 links01, u32 links10, cNorthBridge *nb)
1627  *
1628  *  Description:
1629  *       Set the traffic distribution register for the links provided.
1630  *
1631  *  Parameters:
1632  *      @param[in] u32 links01   = coherent links from node 0 to 1
1633  *      @param[in] u32 links10   = coherent links from node 1 to 0
1634  *      @param[in] cNorthBridge* nb = this northbridge
1635  *
1636  * ---------------------------------------------------------------------------------------
1637  */
1638 static void ht3WriteTrafficDistribution(u32 links01, u32 links10, cNorthBridge *nb)
1639 {
1640 #ifndef HT_BUILD_NC_ONLY
1641         u32 temp;
1642
1643         /* Node 0 */
1644         /* DstLnk */
1645         AmdPCIWriteBits(MAKE_SBDFO(makePCISegmentFromNode(0),
1646                         makePCIBusFromNode(0),
1647                         makePCIDeviceFromNode(0),
1648                         CPU_HTNB_FUNC_00,
1649                         REG_HT_TRAFFIC_DIST_0X164),
1650                         23, 16, &links01);
1651         /* DstNode = 1, cHTPrbDistEn=1, cHTRspDistEn=1, cHTReqDistEn=1 */
1652         temp = 0x0107;
1653         AmdPCIWriteBits(MAKE_SBDFO(makePCISegmentFromNode(0),
1654                         makePCIBusFromNode(0),
1655                         makePCIDeviceFromNode(0),
1656                         CPU_HTNB_FUNC_00,
1657                         REG_HT_TRAFFIC_DIST_0X164),
1658                         15, 0, &temp);
1659
1660         /* Node 1 */
1661         /* DstLnk */
1662         AmdPCIWriteBits(MAKE_SBDFO(makePCISegmentFromNode(1),
1663                         makePCIBusFromNode(1),
1664                         makePCIDeviceFromNode(1),
1665                         CPU_HTNB_FUNC_00,
1666                         REG_HT_TRAFFIC_DIST_0X164),
1667                         23, 16, &links10);
1668         /* DstNode = 0, cHTPrbDistEn=1, cHTRspDistEn=1, cHTReqDistEn=1 */
1669         temp = 0x0007;
1670         AmdPCIWriteBits(MAKE_SBDFO(makePCISegmentFromNode(1),
1671                         makePCIBusFromNode(1),
1672                         makePCIDeviceFromNode(1),
1673                         CPU_HTNB_FUNC_00,
1674                         REG_HT_TRAFFIC_DIST_0X164),
1675                         15, 0, &temp);
1676 #endif /* HT_BUILD_NC_ONLY */
1677 }
1678
1679 /**----------------------------------------------------------------------------------------
1680  *
1681  * static void
1682  * ht1WriteTrafficDistribution(u32 links01, u32 links10, cNorthBridge *nb)
1683  *
1684  *  Description:
1685  *       Traffic distribution is more complex in this case as the routing table must be
1686  *       adjusted to use one link for requests and the other for responses.  Also,
1687  *       perform the buffer tunings on the links required for this config.
1688  *
1689  *  Parameters:
1690  *      @param[in]  u32  links01  = coherent links from node 0 to 1
1691  *      @param[in]  u32  links01  = coherent links from node 1 to 0
1692  *      @param[in]  cNorthBridge* nb = this northbridge
1693  *
1694  * ---------------------------------------------------------------------------------------
1695  */
1696 static void ht1WriteTrafficDistribution(u32 links01, u32 links10, cNorthBridge *nb)
1697 {
1698 #ifndef HT_BUILD_NC_ONLY
1699         u32 route01, route10;
1700         u8 req0, req1, rsp0, rsp1, nclink;
1701
1702         /*
1703          * Get the current request route for 0->1 and 1->0.  This will indicate which of the links
1704          * in links01 are connected to which links in links10.  Since we have to route to distribute
1705          * traffic, we need to know that.       The link used by htinit will become the request, probe link.
1706          * the other link will be used for responses.
1707          */
1708
1709         /* Get the routes, and hang on to them, we will write them back updated. */
1710         AmdPCIRead(MAKE_SBDFO(makePCISegmentFromNode(0),
1711                                 makePCIBusFromNode(0),
1712                                 makePCIDeviceFromNode(0),
1713                                 CPU_HTNB_FUNC_00,
1714                                 REG_ROUTE1_0X44),
1715                                 &route01);
1716         AmdPCIRead(MAKE_SBDFO(makePCISegmentFromNode(1),
1717                                 makePCIBusFromNode(1),
1718                                 makePCIDeviceFromNode(1),
1719                                 CPU_HTNB_FUNC_00,
1720                                 REG_ROUTE0_0X40),
1721                                 &route10);
1722
1723         /* Convert the request routes to a link number.  Note "0xE" is ht1 nb specific.
1724          * Find the response link numbers.
1725         */
1726         ASSERT((route01 & 0xE) && (route10 & 0xE));    /* no route! error! */
1727         req0 = (u8)AmdBitScanReverse((route01 & 0xE)) - 1;
1728         req1 = (u8)AmdBitScanReverse((route10 & 0xE)) - 1;
1729         /* Now, find the other link for the responses */
1730         rsp0 = (u8)AmdBitScanReverse((links01 & ~((u32)1 << req0)));
1731         rsp1 = (u8)AmdBitScanReverse((links10 & ~((u32)1 << req1)));
1732
1733         /* ht1 nb restriction, must have exactly two links */
1734         ASSERT(((((links01 & ~((u32)1 << req0)) & ~((u32)1 << rsp0))) == 0)
1735                 && ((((links10 & ~((u32)1 << req1)) & ~((u32)1 << rsp1))) == 0));
1736
1737         route01 = (route01 & ~0x0E00) | ((u32)0x0100<<(rsp0 + 1));
1738         route10 = (route10 & ~0x0E00) | ((u32)0x0100<<(rsp1 + 1));
1739
1740         AmdPCIWrite(MAKE_SBDFO(makePCISegmentFromNode(0),
1741                                 makePCIBusFromNode(0),
1742                                 makePCIDeviceFromNode(0),
1743                                 CPU_HTNB_FUNC_00,
1744                                 REG_ROUTE1_0X44),
1745                                 &route01);
1746
1747         AmdPCIWrite(MAKE_SBDFO(makePCISegmentFromNode(1),
1748                                 makePCIBusFromNode(1),
1749                                 makePCIDeviceFromNode(1),
1750                                 CPU_HTNB_FUNC_00,
1751                                 REG_ROUTE0_0X40),
1752                                 &route10);
1753
1754         /* While we otherwise do buffer tunings elsewhere, for the dual cHT DP case with
1755          * ht1 northbridges like family 0Fh, do the tunings here where we have all the
1756          * link and route info at hand and don't need to recalculate it.
1757          */
1758
1759         /* Node 0, Request / Probe Link (note family F only has links < 4) */
1760         fam0fWriteHTLinkCmdBufferAlloc(0, req0, 6, 3, 1, 6);
1761         fam0fWriteHTLinkDatBufferAlloc(0, req0, 4, 3, 1);
1762         /* Node 0, Response Link (note family F only has links < 4) */
1763         fam0fWriteHTLinkCmdBufferAlloc(0, rsp0, 1, 0, 15, 0);
1764         fam0fWriteHTLinkDatBufferAlloc(0, rsp0, 1, 1, 6);
1765         /* Node 1, Request / Probe Link (note family F only has links < 4) */
1766         fam0fWriteHTLinkCmdBufferAlloc(1, req1, 6, 3, 1, 6);
1767         fam0fWriteHTLinkDatBufferAlloc(1, req1, 4, 3, 1);
1768         /* Node 1, Response Link (note family F only has links < 4) */
1769         fam0fWriteHTLinkCmdBufferAlloc(1, rsp1, 1, 0, 15, 0);
1770         fam0fWriteHTLinkDatBufferAlloc(1, rsp1, 1, 1, 6);
1771
1772         /* Node 0, is the third link non-coherent? */
1773         nclink = (u8)AmdBitScanReverse(((u8)0x07 & ~((u32)1 << req0) & ~((u32)1 << rsp0)));
1774         if (nb->verifyLinkIsNonCoherent(0, nclink, nb))
1775         {
1776                 fam0fWriteHTLinkCmdBufferAlloc(0, nclink, 6, 5, 2, 0);
1777         }
1778
1779         /* Node 1, is the third link non-coherent? */
1780         nclink = (u8)AmdBitScanReverse(((u8)0x07 & ~((u32)1 << req1) & ~((u32)1 << rsp1)));
1781         if (nb->verifyLinkIsNonCoherent(1, nclink, nb))
1782         {
1783                 fam0fWriteHTLinkCmdBufferAlloc(1, nclink, 6, 5, 2, 0);
1784         }
1785 #endif /* HT_BUILD_NC_ONLY */
1786 }
1787
1788 /**----------------------------------------------------------------------------------------
1789  *
1790  * static void
1791  * fam0fBufferOptimizations(u8 node, sMainData *pDat, cNorthBridge *nb)
1792  *
1793  *  Description:
1794  *       Buffer tunings are inherently northbridge specific. Check for specific configs
1795  *       which require adjustments and apply any standard workarounds to this node.
1796  *
1797  *  Parameters:
1798  *      @param[in]  u8  node      = the node to
1799  *      @param[in]  sMainData *pDat  = coherent links from node 0 to 1
1800  *      @param[in]  cNorthBridge* nb = this northbridge
1801  *
1802  * ---------------------------------------------------------------------------------------
1803  */
1804 static void fam0fBufferOptimizations(u8 node, sMainData *pDat, cNorthBridge *nb)
1805 {
1806 #ifndef HT_BUILD_NC_ONLY
1807         u8 i;
1808         u32 temp;
1809         SBDFO currentPtr;
1810
1811         ASSERT(node < nb->maxNodes);
1812
1813         /* Fix the FIFO pointer register before changing speeds */
1814         currentPtr = MAKE_SBDFO(makePCISegmentFromNode(node),
1815                                 makePCIBusFromNode(node),
1816                                 makePCIDeviceFromNode(node),
1817                                 CPU_NB_FUNC_03,
1818                                 REG_NB_FIFOPTR_3XDC);
1819         for (i=0; i < nb->maxLinks; i++)
1820         {
1821                 temp = 0;
1822                 if (nb->verifyLinkIsCoherent(node, i, nb))
1823                 {
1824                         temp = 0x26;
1825                         ASSERT(i<3);
1826                         AmdPCIWriteBits(currentPtr, 8*i + 5, 8*i, &temp);
1827                 }
1828                 else
1829                 {
1830                         if (nb->verifyLinkIsNonCoherent(node, i, nb))
1831                         {
1832                                 temp = 0x25;
1833                                 ASSERT(i<3);
1834                                 AmdPCIWriteBits(currentPtr, 8*i + 5, 8*i, &temp);
1835                         }
1836                 }
1837         }
1838         /*
1839          * 8P Buffer tuning.
1840          * Either apply the BKDG tunings or, if applicable, apply the more restrictive errata 153
1841          * workaround.
1842          * If 8 nodes, Check this node for 'inner' or 'outer'.
1843          * Tune each link based on coherent or non-coherent
1844          */
1845         if (pDat->NodesDiscovered >= 6)
1846         {
1847                 u8 j;
1848                 BOOL isOuter;
1849                 BOOL isErrata153;
1850
1851                 /* This is for family 0Fh, so assuming dual core max then 7 or 8 nodes are required
1852                  * to be in the situation of 14 or more cores.   We checked nodes above, cross check
1853                  * that the number of cores is 14 or more. We want both 14 cores with at least 7 or 8 nodes
1854                  * not one condition alone, to apply the errata 153 workaround.  Otherwise, 7 or 8 rev F
1855                  * nodes use the BKDG tuning.
1856                  */
1857
1858                 isErrata153 = 0;
1859
1860                 AmdPCIReadBits (MAKE_SBDFO(makePCISegmentFromNode(0),
1861                                         makePCIBusFromNode(0),
1862                                         makePCIDeviceFromNode(0),
1863                                         CPU_HTNB_FUNC_00,
1864                                         REG_NODE_ID_0X60),
1865                                         19, 16, &temp);
1866
1867                 if (temp >= 14)
1868                 {
1869                         /* Check whether we need to do errata 153 tuning or BKDG tuning.
1870                          * Errata 153 applies to JH-1, JH-2 and older.  It is fixed in JH-3
1871                          * (and, one assumes, from there on).
1872                          */
1873                         for (i=0; i < (pDat->NodesDiscovered +1); i++)
1874                         {
1875                                 AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(i),
1876                                                 makePCIBusFromNode(i),
1877                                                 makePCIDeviceFromNode(i),
1878                                                 CPU_NB_FUNC_03,
1879                                                 REG_NB_CPUID_3XFC),
1880                                                 7, 0, &temp);
1881                                 if (((u8)temp & ~0x40) < 0x13)
1882                                 {
1883                                         isErrata153 = 1;
1884                                         break;
1885                                 }
1886                         }
1887                 }
1888
1889                 for (i=0; i < CPU_ADDR_NUM_CONFIG_MAPS; i++)
1890                 {
1891                         isOuter = FALSE;
1892                         /* Check for outer node by scanning the config maps on node 0 for one
1893                          * which is assigned to this node.
1894                          */
1895                         currentPtr = MAKE_SBDFO(makePCISegmentFromNode(0),
1896                                                 makePCIBusFromNode(0),
1897                                                 makePCIDeviceFromNode(0),
1898                                                 CPU_ADDR_FUNC_01,
1899                                                 REG_ADDR_CONFIG_MAP0_1XE0 + (4 * i));
1900                         AmdPCIReadBits (currentPtr, 1, 0, &temp);
1901                         /* Make sure this config map is valid, if it is it will be enabled for read/write */
1902                         if (temp == 3)
1903                         {
1904                                 /* It's valid, get the node (that node is an outer node) */
1905                                 AmdPCIReadBits (currentPtr, 6, 4, &temp);
1906                                 /* Is the node we're working on now? */
1907                                 if (node == (u8)temp)
1908                                 {
1909                                         /* This is an outer node.       Tune it appropriately. */
1910                                         for (j=0; j < nb->maxLinks; j++)
1911                                         {
1912                                                 if (isErrata153)
1913                                                 {
1914                                                         if (nb->verifyLinkIsCoherent(node, j, nb))
1915                                                         {
1916                                                                 fam0fWriteHTLinkCmdBufferAlloc(node, j, 1, 1, 6, 4);
1917                                                         }
1918                                                         else
1919                                                         {
1920                                                                 if (nb->verifyLinkIsNonCoherent(node, j, nb))
1921                                                                 {
1922                                                                         fam0fWriteHTLinkCmdBufferAlloc(node, j, 5, 4, 1, 0);
1923                                                                 }
1924                                                         }
1925                                                 }
1926                                                 else
1927                                                 {
1928                                                         if (nb->verifyLinkIsCoherent(node, j, nb))
1929                                                         {
1930                                                                 fam0fWriteHTLinkCmdBufferAlloc(node, j, 1, 1, 8, 5);
1931                                                         }
1932                                                 }
1933                                         }
1934                                         /*
1935                                          * SRI to XBAR Buffer Counts are correct for outer node at power on defaults.
1936                                          */
1937                                         isOuter = TRUE;
1938                                         break;
1939                                 }
1940                         }
1941                         /* We fill config maps in ascending order, so if we didn't use this one, we're done. */
1942                         else break;
1943                 }
1944                 if (!isOuter)
1945                 {
1946                         if (isErrata153)
1947                         {
1948                                 /* Tuning for inner node coherent links */
1949                                 for (j=0; j < nb->maxLinks; j++)
1950                                 {
1951                                         if (nb->verifyLinkIsCoherent(node, j, nb))
1952                                         {
1953                                                 fam0fWriteHTLinkCmdBufferAlloc(node, j, 2, 1, 5, 4);
1954                                         }
1955
1956                                 }
1957                                 /* SRI to XBAR Buffer Count for inner nodes, zero DReq and DPReq */
1958                                 temp = 0;
1959                                 AmdPCIWriteBits (MAKE_SBDFO(makePCISegmentFromNode(node),
1960                                                         makePCIBusFromNode(node),
1961                                                         makePCIDeviceFromNode(node),
1962                                                         CPU_NB_FUNC_03,
1963                                                         REG_NB_SRI_XBAR_BUF_3X70),
1964                                                         31, 28, &temp);
1965                         }
1966                 }
1967
1968                 /*
1969                  * Tune MCT to XBAR Buffer Count the same an all nodes, 2 Probes, 5 Response
1970                  */
1971                 if (isErrata153)
1972                 {
1973                         temp = 0x25;
1974                         AmdPCIWriteBits (MAKE_SBDFO(makePCISegmentFromNode(node),
1975                                                 makePCIBusFromNode(node),
1976                                                 makePCIDeviceFromNode(node),
1977                                                 CPU_NB_FUNC_03,
1978                                                 REG_NB_MCT_XBAR_BUF_3X78),
1979                                                 14, 8, &temp);
1980                 }
1981         }
1982 #endif /* HT_BUILD_NC_ONLY */
1983 }
1984
1985 /**----------------------------------------------------------------------------------------
1986  *
1987  * static void
1988  * fam10BufferOptimizations(u8 node, sMainData *pDat, cNorthBridge *nb)
1989  *
1990  *  Description:
1991  *       Buffer tunings are inherently northbridge specific. Check for specific configs
1992  *       which require adjustments and apply any standard workarounds to this node.
1993  *
1994  *  Parameters:
1995  *      @param[in] u8 node       = the node to tune
1996  *      @param[in] sMainData *pDat  = global state
1997  *      @param[in] cNorthBridge* nb = this northbridge
1998  *
1999  * ---------------------------------------------------------------------------------------
2000  */
2001 static void fam10BufferOptimizations(u8 node, sMainData *pDat, cNorthBridge *nb)
2002 {
2003         u32 temp;
2004         SBDFO currentPtr;
2005         u8 i;
2006
2007         ASSERT(node < nb->maxNodes);
2008
2009         /*
2010          * Link to XCS Token Count Tuning
2011          *
2012          * For each active link that we reganged (so this unfortunately can't go into the PCI reg
2013          * table), we have to switch the Link to XCS Token Counts to the ganged state.
2014          * We do this here for the non-uma case, which is to write the values that would have
2015          * been power on defaults if the link was ganged at cold reset.
2016          */
2017         for (i = 0; i < pDat->TotalLinks*2; i++)
2018         {
2019                 if ((pDat->PortList[i].NodeID == node) && (pDat->PortList[i].Type == PORTLIST_TYPE_CPU))
2020                 {
2021                         /* If the link is greater than 4, this is a sublink 1, so it is not reganged. */
2022                         if (pDat->PortList[i].Link < 4)
2023                         {
2024                                 currentPtr = MAKE_SBDFO(makePCISegmentFromNode(node),
2025                                                 makePCIBusFromNode(node),
2026                                                 makePCIDeviceFromNode(node),
2027                                                 CPU_NB_FUNC_03,
2028                                                 REG_NB_LINK_XCS_TOKEN0_3X148 + 4*pDat->PortList[i].Link);
2029                                 if (pDat->PortList[i].SelRegang)
2030                                 {
2031                                         /* Handle all the regang Token count adjustments */
2032
2033                                         /* Sublink 0: [Probe0tok] = 2 [Rsp0tok] = 2 [PReq0tok] = 2 [Req0tok] = 2 */
2034                                         temp = 0xAA;
2035                                         AmdPCIWriteBits(currentPtr, 7, 0, &temp);
2036                                         /* Sublink 1: [Probe1tok] = 0 [Rsp1tok] = 0 [PReq1tok] = 0 [Req1tok] = 0 */
2037                                         temp = 0;
2038                                         AmdPCIWriteBits(currentPtr, 23, 16, &temp);
2039                                         /* [FreeTok] = 3 */
2040                                         temp = 3;
2041                                         AmdPCIWriteBits(currentPtr, 15, 14, &temp);
2042                                 }
2043                                 else
2044                                 {
2045                                         /* Read the regang bit in hardware */
2046                                         AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(pDat->PortList[i].NodeID),
2047                                                         makePCIBusFromNode(pDat->PortList[i].NodeID),
2048                                                         makePCIDeviceFromNode(pDat->PortList[i].NodeID),
2049                                                         CPU_HTNB_FUNC_00,
2050                                                         REG_HT_LINK_EXT_CONTROL0_0X170 + 4*pDat->PortList[i].Link),
2051                                                         0, 0, &temp);
2052                                         if (temp == 1)
2053                                         {
2054                                                 /* handle a minor adjustment for stapped ganged links.   If SelRegang is false we
2055                                                  * didn't do the regang, so if the bit is on then it's hardware strapped.
2056                                                  */
2057
2058                                                 /* [FreeTok] = 3 */
2059                                                 temp = 3;
2060                                                 AmdPCIWriteBits(currentPtr, 15, 14, &temp);
2061                                         }
2062                                 }
2063                         }
2064                 }
2065         }
2066 }
2067
2068 /*
2069  * North Bridge 'constructor'.
2070  *
2071  */
2072
2073 /**----------------------------------------------------------------------------------------
2074  *
2075  * void
2076  * newNorthBridge(u8 node, cNorthBridge *nb)
2077  *
2078  *  Description:
2079  *       Construct a new northbridge.  This routine encapsulates knowledge of how to tell
2080  *       significant differences between families of supported northbridges and what routines
2081  *       can be used in common and which are unique.  A fully populated northbridge interface
2082  *       is provided by nb.
2083  *
2084  *  Parameters:
2085  *        @param[in]        node          u8             = create a northbridge interface for this node.
2086  *        @param[out]       cNorthBridge* nb             = the caller's northbridge structure to initialize.
2087  *
2088  * ---------------------------------------------------------------------------------------
2089  */
2090 void newNorthBridge(u8 node, cNorthBridge *nb)
2091 {
2092         u32 match;
2093         u32 extFam, baseFam, model;
2094
2095         cNorthBridge fam10 =
2096         {
2097 #ifdef HT_BUILD_NC_ONLY
2098                 8,
2099                 1,
2100                 12,
2101 #else
2102                 8,
2103                 8,
2104                 64,
2105 #endif /* HT_BUILD_NC_ONLY*/
2106                 writeRoutingTable,
2107                 writeNodeID,
2108                 readDefLnk,
2109                 enableRoutingTables,
2110                 verifyLinkIsCoherent,
2111                 readTrueLinkFailStatus,
2112                 readToken,
2113                 writeToken,
2114                 fam10GetNumCoresOnNode,
2115                 setTotalNodesAndCores,
2116                 limitNodes,
2117                 writeFullRoutingTable,
2118                 isCompatible,
2119                 fam10IsCapable,
2120                 (void (*)(u8, u8, cNorthBridge*))commonVoid,
2121                 (BOOL (*)(u8, u8, sMainData*, cNorthBridge*))commonReturnFalse,
2122                 readSbLink,
2123                 verifyLinkIsNonCoherent,
2124                 ht3SetCFGAddrMap,
2125                 convertBitsToWidth,
2126                 convertWidthToBits,
2127                 fam10NorthBridgeFreqMask,
2128                 gatherLinkData,
2129                 setLinkData,
2130                 ht3WriteTrafficDistribution,
2131                 fam10BufferOptimizations,
2132                 0x00000001,
2133                 0x00000200,
2134                 18,
2135                 0x00000f01
2136         };
2137
2138         cNorthBridge fam0f =
2139         {
2140 #ifdef HT_BUILD_NC_ONLY
2141                 3,
2142                 1,
2143                 12,
2144 #else
2145                 3,
2146                 8,
2147                 32,
2148 #endif /* HT_BUILD_NC_ONLY*/
2149                 writeRoutingTable,
2150                 writeNodeID,
2151                 readDefLnk,
2152                 enableRoutingTables,
2153                 verifyLinkIsCoherent,
2154                 readTrueLinkFailStatus,
2155                 readToken,
2156                 writeToken,
2157                 fam0FGetNumCoresOnNode,
2158                 setTotalNodesAndCores,
2159                 limitNodes,
2160                 writeFullRoutingTable,
2161                 isCompatible,
2162                 fam0fIsCapable,
2163                 fam0fStopLink,
2164                 (BOOL (*)(u8, u8, sMainData*, cNorthBridge*))commonReturnFalse,
2165                 readSbLink,
2166                 verifyLinkIsNonCoherent,
2167                 ht1SetCFGAddrMap,
2168                 convertBitsToWidth,
2169                 convertWidthToBits,
2170                 ht1NorthBridgeFreqMask,
2171                 gatherLinkData,
2172                 setLinkData,
2173                 ht1WriteTrafficDistribution,
2174                 fam0fBufferOptimizations,
2175                 0x00000001,
2176                 0x00000100,
2177                 16,
2178                 0x00000f00
2179         };
2180
2181         /* Start with enough of the key to identify the northbridge interface */
2182         AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(node),
2183                         makePCIBusFromNode(node),
2184                         makePCIDeviceFromNode(node),
2185                         CPU_NB_FUNC_03,
2186                         REG_NB_CPUID_3XFC),
2187                         27, 20, &extFam);
2188         AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(node),
2189                         makePCIBusFromNode(node),
2190                         makePCIDeviceFromNode(node),
2191                         CPU_NB_FUNC_03,
2192                         REG_NB_CPUID_3XFC),
2193                         11, 8, &baseFam);
2194         AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(node),
2195                         makePCIBusFromNode(node),
2196                         makePCIDeviceFromNode(node),
2197                         CPU_NB_FUNC_03,
2198                         REG_NB_CPUID_3XFC),
2199                         7, 4, &model);
2200         match = (u32)((baseFam << 8) | extFam);
2201
2202         /* Test each in turn looking for a match.       Init the struct if found */
2203         if (match == fam10.compatibleKey)
2204         {
2205                 Amdmemcpy((void *)nb, (const void *)&fam10, (u32) sizeof(cNorthBridge));
2206         }
2207         else
2208         {
2209                 if (match == fam0f.compatibleKey)
2210                 {
2211                         Amdmemcpy((void *)nb, (const void *)&fam0f, (u32) sizeof(cNorthBridge));
2212                 }
2213                 else
2214                 {
2215                 STOP_HERE;
2216                 }
2217         }
2218
2219         /* Update the initial limited key to the real one, which may include other matching info */
2220         nb->compatibleKey = makeKey(node);
2221 }
2222