AGESA F15: AMD family15 AGESA code
[coreboot.git] / src / vendorcode / amd / agesa / f15 / Proc / HT / NbCommon / htNbUtilities.c
1 /* $NoKeywords:$ */
2 /**
3  * @file
4  *
5  * Northbridge utility routines.
6  *
7  * These routines are needed for support of more than one feature area.
8  * Collect them in this file so build options don't remove them.
9  *
10  * @xrefitem bom "File Content Label" "Release Content"
11  * @e project:      AGESA
12  * @e sub-project:  HyperTransport
13  * @e \$Revision: 56279 $   @e \$Date: 2011-07-11 13:11:28 -0600 (Mon, 11 Jul 2011) $
14  *
15  */
16 /*
17 *****************************************************************************
18 *
19 * Copyright (C) 2012 Advanced Micro Devices, Inc.
20 * All rights reserved.
21 *
22 * Redistribution and use in source and binary forms, with or without
23 * modification, are permitted provided that the following conditions are met:
24 *     * Redistributions of source code must retain the above copyright
25 *       notice, this list of conditions and the following disclaimer.
26 *     * Redistributions in binary form must reproduce the above copyright
27 *       notice, this list of conditions and the following disclaimer in the
28 *       documentation and/or other materials provided with the distribution.
29 *     * Neither the name of Advanced Micro Devices, Inc. nor the names of
30 *       its contributors may be used to endorse or promote products derived
31 *       from this software without specific prior written permission.
32 *
33 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
34 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
35 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 * DISCLAIMED. IN NO EVENT SHALL ADVANCED MICRO DEVICES, INC. BE LIABLE FOR ANY
37 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
38 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
39 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
40 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
41 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
42 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
43 *
44 * ***************************************************************************
45 *
46 */
47
48 /*
49  *----------------------------------------------------------------------------
50  *                                MODULES USED
51  *
52  *----------------------------------------------------------------------------
53  */
54
55
56
57 #include "AGESA.h"
58 #include "amdlib.h"
59 #include "Ids.h"
60 #include "Topology.h"
61 #include "htFeat.h"
62 #include "htNotify.h"
63 #include "htNb.h"
64 #include "htNbCommonHardware.h"
65 #include "htNbUtilities.h"
66 #include "Filecode.h"
67 CODE_GROUP (G1_PEICC)
68 RDATA_GROUP (G2_PEI)
69
70 #define FILECODE PROC_HT_NBCOMMON_HTNBUTILITIES_FILECODE
71 /*----------------------------------------------------------------------------
72  *                          DEFINITIONS AND MACROS
73  *
74  *----------------------------------------------------------------------------
75  */
76
77 /*----------------------------------------------------------------------------------------*/
78 /**
79  * Return the HT Host capability base PCI config address for a Link.
80  *
81  * @HtNbMethod{::F_MAKE_LINK_BASE}
82  *
83  * @param[in]     Node    the Node this Link is on
84  * @param[in]     Link    the Link
85  * @param[in]     Nb      this northbridge
86  *
87  * @return  the pci config address
88  */
89 PCI_ADDR
90 MakeLinkBase (
91   IN       UINT8       Node,
92   IN       UINT8       Link,
93   IN       NORTHBRIDGE *Nb
94   )
95 {
96   PCI_ADDR LinkBase;
97
98   ASSERT (Nb != NULL);
99   if (Link < 4) {
100     LinkBase.AddressValue = MAKE_SBDFO (MakePciSegmentFromNode (Node),
101                                         MakePciBusFromNode (Node),
102                                         MakePciDeviceFromNode (Node),
103                                         CPU_HTNB_FUNC_00,
104                                         REG_HT_CAP_BASE_0X80 + Link*HT_HOST_CAP_SIZE);
105   } else {
106     LinkBase.AddressValue = MAKE_SBDFO (MakePciSegmentFromNode (Node),
107                                         MakePciBusFromNode (Node),
108                                         MakePciDeviceFromNode (Node),
109                                         CPU_HTNB_FUNC_04,
110                                         REG_HT_CAP_BASE_0X80 + (Link - 4)*HT_HOST_CAP_SIZE);
111   }
112   return LinkBase;
113 }
114
115 /*----------------------------------------------------------------------------------------*/
116 /**
117  * Return the LinkFailed status AFTER an attempt is made to clear the bit.
118  *
119  * @HtNbMethod{::F_READ_TRUE_LINK_FAIL_STATUS}
120  *
121  * Dependency!:  HT_FEATURES::SetHtControlRegisterBits
122  *
123  * Also, call event notify if a Hardware Fault caused a sync flood on a previous boot.
124  *
125  * The table below summarizes correct responses of this routine.
126  * <TABLE>
127  *   <TR><TD> Family </TD> <TD> before </TD> <TD> after </TD> <TD> unconnected </TD> <TD> Notify? </TD> <TD> return </TD></TR>
128  *   <TR><TD>  10    </TD> <TD>   0    </TD> <TD>   0   </TD> <TD>     0       </TD> <TD>   No    </TD> <TD> FALSE  </TD></TR>
129  *   <TR><TD>  10    </TD> <TD>   1    </TD> <TD>   0   </TD> <TD>     0       </TD> <TD>   Yes   </TD> <TD> FALSE  </TD></TR>
130  *   <TR><TD>  10    </TD> <TD>   1    </TD> <TD>   0   </TD> <TD>     3       </TD> <TD>   No    </TD> <TD> TRUE   </TD></TR>
131  * </TABLE>
132  *
133  * @param[in]     Node   the Node that will be examined
134  * @param[in]     Link   the Link on that Node to examine
135  * @param[in]     State  access to call back routine
136  * @param[in]     Nb     this northbridge
137  *
138  * @retval        TRUE   the Link is not connected or has hard error
139  * @retval        FALSE  the Link is connected
140  */
141 BOOLEAN
142 ReadTrueLinkFailStatus (
143   IN       UINT8       Node,
144   IN       UINT8       Link,
145   IN       STATE_DATA  *State,
146   IN       NORTHBRIDGE *Nb
147   )
148 {
149   UINT32    Before;
150   UINT32    After;
151   UINT32    Unconnected;
152   UINT32    Crc;
153   PCI_ADDR  Reg;
154
155   ASSERT ((Node < MAX_NODES) && (Link < Nb->MaxLinks));
156
157   Reg = Nb->MakeLinkBase (Node, Link, Nb);
158   Reg.Address.Register +=  HTHOST_LINK_CONTROL_REG;
159
160   // Save the CRC status before doing anything else.
161   // Read, Clear, re-read the error bits in the Link Control Register
162   // (FN0_84/A4/C4[4] = LinkFail bit),
163   // and check the connection status, TransOff and EndOfChain.
164   //
165   LibAmdPciReadBits (Reg, 9, 8, &Crc, Nb->ConfigHandle);
166   LibAmdPciReadBits (Reg, 4, 4, &Before, Nb->ConfigHandle);
167   State->HtFeatures->SetHtControlRegisterBits (Reg, 4, 4, &Before, State);
168   LibAmdPciReadBits (Reg, 4, 4, &After, Nb->ConfigHandle);
169   LibAmdPciReadBits (Reg, 7, 6, &Unconnected, Nb->ConfigHandle);
170
171   if (Before != After) {
172     if (Unconnected == 0) {
173       if (Crc != 0) {
174         // A sync flood occurred due to HT CRC
175         // Pass the Node and Link on which the generic sync flood event occurred.
176         NotifyAlertHwHtCrc (Node, Link, (UINT8)Crc, State);
177       } else {
178         // Some sync flood occurred
179         // Pass the Node and Link on which the generic sync flood event occurred.
180         NotifyAlertHwSyncFlood (Node, Link, State);
181       }
182     }
183   }
184   return (BOOLEAN) ((After != 0) || (Unconnected != 0));
185 }
186
187 /*----------------------------------------------------------------------------------------*/
188 /**
189  * Write the total number of cores and Nodes to the Node
190  *
191  * @HtNbMethod{::F_SET_TOTAL_NODES_AND_CORES}
192  *
193  * @param[in]     Node         the Node that will be examined
194  * @param[in]     TotalNodes   the total number of Nodes
195  * @param[in]     TotalCores   the total number of cores
196  * @param[in]     Nb           this northbridge
197  */
198 VOID
199 SetTotalNodesAndCores (
200   IN       UINT8       Node,
201   IN       UINT8       TotalNodes,
202   IN       UINT8       TotalCores,
203   IN       NORTHBRIDGE *Nb
204   )
205 {
206   PCI_ADDR NodeIDReg;
207   UINT32 Temp;
208
209   ASSERT ((Node < MAX_NODES) && (TotalNodes <= MAX_NODES));
210   NodeIDReg.AddressValue = MAKE_SBDFO (MakePciSegmentFromNode (Node),
211                                        MakePciBusFromNode (Node),
212                                        MakePciDeviceFromNode (Node),
213                                        CPU_HTNB_FUNC_00,
214                                        REG_NODE_ID_0X60);
215
216   Temp = ((TotalCores - 1) & HTREG_NODE_CPUCNT_4_0);
217   LibAmdPciWriteBits (NodeIDReg, 20, 16, &Temp, Nb->ConfigHandle);
218   Temp = TotalNodes - 1;
219   LibAmdPciWriteBits (NodeIDReg,  6,  4, &Temp, Nb->ConfigHandle);
220
221   NodeIDReg.Address.Register = REG_HT_EXTENDED_NODE_ID_F0X160;
222
223   Temp = (((TotalCores - 1) & HTREG_EXTNODE_CPUCNT_7_5) >> 5);
224   LibAmdPciWriteBits (NodeIDReg, 18, 16, &Temp, Nb->ConfigHandle);
225 }
226
227 /*----------------------------------------------------------------------------------------*/
228 /**
229  * Get the Count (1 based) of Nodes in the system.
230  *
231  * @HtNbMethod{::F_GET_NODE_COUNT}
232  *
233  * This is intended to support AP Core HT init, since the Discovery State data is not
234  * available (State->NodesDiscovered), there needs to be this way to find the number
235  * of Nodes.  The Node count can be read from the BSP.
236  *
237  * @param[in]     Nb           this northbridge
238  *
239  * @return        The number of nodes
240  */
241 UINT8
242 GetNodeCount (
243   IN       NORTHBRIDGE *Nb
244   )
245 {
246   PCI_ADDR NodeIDReg;
247   UINT32 Temp;
248
249   NodeIDReg.AddressValue = MAKE_SBDFO (MakePciSegmentFromNode (0),
250                                        MakePciBusFromNode (0),
251                                        MakePciDeviceFromNode (0),
252                                        CPU_HTNB_FUNC_00,
253                                        REG_NODE_ID_0X60);
254   LibAmdPciReadBits (NodeIDReg,  6,  4, &Temp, Nb->ConfigHandle);
255   return ((UINT8) (++Temp));
256 }
257
258 /*----------------------------------------------------------------------------------------*/
259 /**
260  * Limit coherent config accesses to cpus as indicated by Nodecnt.
261  *
262  * @HtNbMethod{::F_LIMIT_NODES}
263  *
264  * @param[in]     Node    the Node that will be examined
265  * @param[in]     Nb      this northbridge
266  */
267 VOID
268 LimitNodes (
269   IN       UINT8       Node,
270   IN       NORTHBRIDGE *Nb
271   )
272 {
273   UINT32 Temp;
274   PCI_ADDR Reg;
275
276   Temp = 1;
277   ASSERT ((Node < MAX_NODES));
278   Reg.AddressValue = MAKE_SBDFO (MakePciSegmentFromNode (Node),
279                                  MakePciBusFromNode (Node),
280                                  MakePciDeviceFromNode (Node),
281                                  CPU_HTNB_FUNC_00,
282                                  REG_LINK_TRANS_CONTROL_0X68);
283   LibAmdPciWriteBits (Reg, 15, 15, &Temp, Nb->ConfigHandle);
284 }
285
286 /*----------------------------------------------------------------------------------------*/
287 /**
288  * Get the Package Link number, given the node and real link number.
289  *
290  * @HtNbMethod{::F_GET_PACKAGE_LINK}
291  *
292  * Based on the link to package link mapping from BKDG, look up package link for
293  * the input link on the internal node number corresponding to Node id.
294  *
295  * @param[in]   Node       the node which has this link
296  * @param[in]   Link       the link on that node
297  * @param[in]   Nb         this northbridge
298  *
299  * @return      the Package Link, HT_LIST_TERMINAL Not connected in package, HT_LIST_MATCH_INTERNAL_LINK package internal link.
300  *
301  */
302 UINT8
303 GetPackageLink (
304   IN       UINT8       Node,
305   IN       UINT8       Link,
306   IN       NORTHBRIDGE *Nb
307   )
308 {
309   UINT8 ModuleType;
310   UINT8 Module;
311   UINTN PackageLinkMapItem;
312   UINT8 PackageLink;
313
314   ASSERT ((Node < MAX_NODES) && (Link < Nb->MaxLinks));
315   PackageLink = HT_LIST_TERMINAL;
316
317   Nb->GetModuleInfo (Node, &ModuleType, &Module, Nb);
318
319   if (ModuleType != 0) {
320     ASSERT (Nb->PackageLinkMap != NULL);
321     // Use table to find this module's package link
322     PackageLinkMapItem = 0;
323     while ((*Nb->PackageLinkMap)[PackageLinkMapItem].Link != HT_LIST_TERMINAL) {
324       if (((*Nb->PackageLinkMap)[PackageLinkMapItem].Module == Module) &&
325           ((*Nb->PackageLinkMap)[PackageLinkMapItem].Link == Link)) {
326         PackageLink = (*Nb->PackageLinkMap)[PackageLinkMapItem].PackageLink;
327         break;
328       }
329       PackageLinkMapItem++;
330     }
331   } else {
332     PackageLink = Link;
333   }
334   return PackageLink;
335 }