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