AGESA F15: AMD family15 AGESA code
[coreboot.git] / src / vendorcode / amd / agesa / f15 / Proc / HT / Features / htFeatNoncoherent.c
1 /* $NoKeywords:$ */
2 /**
3  * @file
4  *
5  * Non-Coherent Discovery Routines.
6  *
7  * Contains routines for enumerating and initializing non-coherent devices.
8  *
9  * @xrefitem bom "File Content Label" "Release Content"
10  * @e project:      AGESA
11  * @e sub-project:  HyperTransport
12  * @e \$Revision: 56279 $   @e \$Date: 2011-07-11 13:11:28 -0600 (Mon, 11 Jul 2011) $
13  *
14  */
15 /*
16 *****************************************************************************
17 *
18 * Copyright (C) 2012 Advanced Micro Devices, Inc.
19 * All rights reserved.
20 *
21 * Redistribution and use in source and binary forms, with or without
22 * modification, are permitted provided that the following conditions are met:
23 *     * Redistributions of source code must retain the above copyright
24 *       notice, this list of conditions and the following disclaimer.
25 *     * Redistributions in binary form must reproduce the above copyright
26 *       notice, this list of conditions and the following disclaimer in the
27 *       documentation and/or other materials provided with the distribution.
28 *     * Neither the name of Advanced Micro Devices, Inc. nor the names of
29 *       its contributors may be used to endorse or promote products derived
30 *       from this software without specific prior written permission.
31 *
32 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
33 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
34 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
35 * DISCLAIMED. IN NO EVENT SHALL ADVANCED MICRO DEVICES, INC. BE LIABLE FOR ANY
36 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
37 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
38 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
39 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
40 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
41 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42 *
43 * ***************************************************************************
44 *
45 */
46
47 /*
48  *----------------------------------------------------------------------------
49  *                                MODULES USED
50  *
51  *----------------------------------------------------------------------------
52  */
53
54
55
56 #include "AGESA.h"
57 #include "amdlib.h"
58 #include "Ids.h"
59 #include "Topology.h"
60 #include "htFeat.h"
61 #include "htInterface.h"
62 #include "htNotify.h"
63 #include "htNb.h"
64 #include "htFeatNoncoherent.h"
65 #include "htFeatOptimization.h"
66 #include "Filecode.h"
67 CODE_GROUP (G1_PEICC)
68 RDATA_GROUP (G2_PEI)
69
70 #define FILECODE PROC_HT_FEATURES_HTFEATNONCOHERENT_FILECODE
71 /*----------------------------------------------------------------------------
72  *                          DEFINITIONS AND MACROS
73  *
74  *----------------------------------------------------------------------------
75  */
76 #define NO_DEVICE 0xFFFFFFFFull
77
78 /*----------------------------------------------------------------------------
79  *                           TYPEDEFS AND STRUCTURES
80  *
81  *----------------------------------------------------------------------------
82  */
83
84 /*----------------------------------------------------------------------------
85  *                        PROTOTYPES OF LOCAL FUNCTIONS
86  *
87  *----------------------------------------------------------------------------
88  */
89
90 /*----------------------------------------------------------------------------
91  *                            EXPORTED FUNCTIONS
92  *
93  *----------------------------------------------------------------------------
94  */
95
96 /*----------------------------------------------------------------------------
97  *                              LOCAL FUNCTIONS
98  *
99  *----------------------------------------------------------------------------
100  */
101
102 /***************************************************************************
103  ***                       Non-coherent init code                        ***
104  ***                             Algorithms                              ***
105  ***************************************************************************/
106 /*----------------------------------------------------------------------------------------*/
107 /**
108  * Process a non-coherent Link.
109  *
110  * @HtFeatMethod{::F_PROCESS_LINK}
111  *
112  * Enable a range of bus numbers, and set the device ID for all devices found.  Add
113  * non-coherent devices, links to the system data structure.
114  *
115  * @param[in]     Node          Node on which to process nc init
116  * @param[in]     Link          The non-coherent Link on that Node
117  * @param[in]     IsCompatChain Is this the chain with the southbridge? TRUE if yes.
118  * @param[in,out] State         our global state
119  */
120 VOID
121 ProcessLink (
122   IN       UINT8         Node,
123   IN       UINT8         Link,
124   IN       BOOLEAN       IsCompatChain,
125   IN OUT   STATE_DATA    *State
126   )
127 {
128   UINT8 SecBus;
129   UINT8 SubBus;
130   UINT32 CurrentBuid;
131   UINT32 Temp;
132   UINT32 UnitIdCount;
133   PCI_ADDR CurrentPtr;
134   PCI_ADDR Link1ControlRegister;
135   UINT8 Depth;
136   BUID_SWAP_LIST *SwapPtr;
137   UINT8  LastLink;
138   BOOLEAN IsCaveDevice;
139
140   ASSERT ((Node < MAX_NODES) && (Link < State->Nb->MaxLinks));
141
142   if (!State->HtInterface->GetOverrideBusNumbers (Node, Link, &SecBus, &SubBus, State)) {
143     // Assign Bus numbers
144     if (State->AutoBusCurrent >= State->HtBlock->AutoBusMax) {
145       //  If we run out of Bus Numbers, notify and skip this chain
146       //
147       IDS_ERROR_TRAP;
148       NotifyErrorNcohBusMaxExceed (Node, Link, State->AutoBusCurrent, State);
149       return;
150     }
151
152     if (State->UsedCfgMapEntries >= 4) {
153       // If we have used all the PCI Config maps we can't add another chain.
154       // Notify and if call back is unimplemented or returns, skip this chain.
155       //
156       IDS_ERROR_TRAP;
157       NotifyErrorNcohCfgMapExceed (Node, Link, State);
158       return;
159     }
160
161     SecBus = State->AutoBusCurrent;
162     SubBus = SecBus + State->HtBlock->AutoBusIncrement - 1;
163     State->AutoBusCurrent = State->AutoBusCurrent + State->HtBlock->AutoBusIncrement;
164   }
165
166   State->Nb->SetConfigAddrMap (State->UsedCfgMapEntries, SecBus, SubBus, Node, Link, State, State->Nb);
167   State->UsedCfgMapEntries++;
168
169   if (State->HtInterface->GetManualBuidSwapList (Node, Link, &SwapPtr, State)) {
170     // Manual non-coherent BUID assignment
171     AGESA_TESTPOINT (TpProcHtManualNc, State->ConfigHandle);
172
173
174     if (!IsCompatChain || !State->IsUsingRecoveryHt) {
175       //  If this is the not southbridge chain or Recovery HT was not used
176       // then we need to assign BUIDs here.
177       //
178       Depth = 0;
179       // Assign BUID's per manual override
180       while (SwapPtr->Swaps[Depth].FromId != 0xFF) {
181         CurrentPtr.AddressValue = MAKE_SBDFO (0, SecBus, SwapPtr->Swaps[Depth].FromId, 0, 0);
182         if (DoesDeviceHaveHtSubtypeCap (CurrentPtr, HT_SLAVE_CAPABILITY, &CurrentPtr, State)) {
183           // Set the device's BUID field [20:16] to the current buid
184           CurrentBuid = SwapPtr->Swaps[Depth].ToId;
185           LibAmdPciWriteBits (CurrentPtr, 20, 16, &CurrentBuid, State->ConfigHandle);
186           Depth++;
187         } else {
188           // All non-coherent devices must have a slave interface capability.
189           ASSERT (FALSE);
190           break;
191         }
192       }
193     }
194
195     // Build chain of devices. Do this even if Recovery HT assign BUIDs for this chain.
196     Depth = 0;
197     while (SwapPtr->FinalIds[Depth] != 0xFF) {
198       ASSERT (State->TotalLinks < MAX_PLATFORM_LINKS);
199       (*State->PortList)[(State->TotalLinks * 2)].NodeID = Node;
200       // Note: depth == 0 is true before depth > 0. This makes LastLink variable work.
201       if (Depth == 0) {
202         (*State->PortList)[(State->TotalLinks * 2)].Type = PORTLIST_TYPE_CPU;
203         (*State->PortList)[(State->TotalLinks * 2)].Link = Link;
204       } else {
205         // Fill in the host side port.  Link and base pointer can be deduced from the upstream link's
206         // downstream port.
207         (*State->PortList)[(State->TotalLinks * 2)].Type = PORTLIST_TYPE_IO;
208         (*State->PortList)[(State->TotalLinks * 2)].Link = 1 - (*State->PortList)[(((State->TotalLinks - 1) * 2) + 1)].Link;
209         (*State->PortList)[(State->TotalLinks * 2)].HostLink = Link;
210         (*State->PortList)[(State->TotalLinks * 2)].HostDepth = Depth - 1;
211         (*State->PortList)[(State->TotalLinks * 2)].Pointer = (*State->PortList)[(((State->TotalLinks - 1) * 2) + 1)].Pointer;
212       }
213
214       (*State->PortList)[(State->TotalLinks * 2) + 1].Type = PORTLIST_TYPE_IO;
215       (*State->PortList)[(State->TotalLinks * 2) + 1].NodeID = Node;
216       (*State->PortList)[(State->TotalLinks * 2) + 1].HostLink = Link;
217       (*State->PortList)[(State->TotalLinks * 2) + 1].HostDepth = Depth;
218
219       CurrentPtr.AddressValue = MAKE_SBDFO (0, SecBus, (SwapPtr->FinalIds[Depth] & 0x3F), 0, 0);
220       if (DoesDeviceHaveHtSubtypeCap (CurrentPtr, HT_SLAVE_CAPABILITY, &CurrentPtr, State)) {
221         (*State->PortList)[(State->TotalLinks * 2) + 1].Pointer = CurrentPtr;
222       } else {
223         // All non-coherent devices must have a slave interface capability.
224         ASSERT (FALSE);
225         break;
226       }
227
228       // Bit 6 indicates whether orientation override is desired.
229       // Bit 7 indicates the upstream Link if overriding.
230       //
231       // assert catches at least the one known incorrect setting, that a non-zero link
232       // is specified, but override desired is not set.
233       ASSERT (((SwapPtr->FinalIds[Depth] & 0x40) != 0) || ((SwapPtr->FinalIds[Depth] & 0x80) == 0));
234       if ((SwapPtr->FinalIds[Depth] & 0x40) != 0) {
235         // Override the device's orientation
236         LastLink = SwapPtr->FinalIds[Depth] >> 7;
237       } else {
238         // Detect the device's orientation, by reading the Master Host bit [26]
239         LibAmdPciReadBits (CurrentPtr, 26, 26, &Temp, State->ConfigHandle);
240         LastLink = (UINT8)Temp;
241       }
242       (*State->PortList)[(State->TotalLinks * 2) + 1].Link = LastLink;
243
244       Depth++;
245       State->TotalLinks++;
246     }
247   } else {
248     // Automatic non-coherent device detection
249     AGESA_TESTPOINT (TpProcHtAutoNc, State->ConfigHandle);
250     IDS_HDT_CONSOLE (HT_TRACE, "Auto IO chain init on node=%d, link=%d, secbus=%d, subbus=%d%s.\n",
251                      Node, Link, SecBus, SubBus, (IsCompatChain ? ", Compat" : ""));
252     Depth = 0;
253     CurrentBuid = 1;
254     for (; ; ) {
255       CurrentPtr.AddressValue = MAKE_SBDFO (0, SecBus, 0, 0, 0);
256
257       LibAmdPciRead (AccessWidth32, CurrentPtr, &Temp, State->ConfigHandle);
258       if (Temp == NO_DEVICE) {
259         if (IsCompatChain && State->IsUsingRecoveryHt) {
260           // See if the device is aleady at a non-zero BUID because HT Init Reset aleady assigned it.
261           CurrentPtr.Address.Device = CurrentBuid;
262           LibAmdPciRead (AccessWidth32, CurrentPtr, &Temp, State->ConfigHandle);
263           if (Temp == NO_DEVICE) {
264             // No more devices already assigned.
265             break;
266           }
267         } else {
268           // No more devices found.
269           break;
270         }
271       }
272
273       ASSERT (State->TotalLinks < MAX_PLATFORM_LINKS);
274
275       (*State->PortList)[(State->TotalLinks * 2)].NodeID = Node;
276       if (Depth == 0) {
277         (*State->PortList)[(State->TotalLinks * 2)].Type = PORTLIST_TYPE_CPU;
278         (*State->PortList)[(State->TotalLinks * 2)].Link = Link;
279       } else {
280         // Fill in the host side port.  Link and base pointer can be deduced from the upstream link's
281         // downstream port.
282         (*State->PortList)[(State->TotalLinks * 2)].Type = PORTLIST_TYPE_IO;
283         (*State->PortList)[(State->TotalLinks * 2)].Link = 1 - (*State->PortList)[((State->TotalLinks - 1) * 2) + 1].Link;
284         (*State->PortList)[(State->TotalLinks * 2)].HostLink = Link;
285         (*State->PortList)[(State->TotalLinks * 2)].HostDepth = Depth - 1;
286         (*State->PortList)[(State->TotalLinks * 2)].Pointer = (*State->PortList)[((State->TotalLinks - 1) * 2) + 1].Pointer;
287       }
288
289       (*State->PortList)[(State->TotalLinks * 2) + 1].Type = PORTLIST_TYPE_IO;
290       (*State->PortList)[(State->TotalLinks * 2) + 1].NodeID = Node;
291       (*State->PortList)[(State->TotalLinks * 2) + 1].HostLink = Link;
292       (*State->PortList)[(State->TotalLinks * 2) + 1].HostDepth = Depth;
293
294       if (DoesDeviceHaveHtSubtypeCap (CurrentPtr, HT_SLAVE_CAPABILITY, &CurrentPtr, State)) {
295
296         // Get device's unit id count [25:21]
297         LibAmdPciReadBits (CurrentPtr, 25, 21, &UnitIdCount, State->ConfigHandle);
298         if (((UnitIdCount + CurrentBuid) > MAX_BUID) || ((SecBus == 0) && ((UnitIdCount + CurrentBuid) > 24))) {
299           // An error handler for the case where we run out of BUID's on a chain
300           NotifyErrorNcohBuidExceed (Node, Link, Depth, (UINT8)CurrentBuid, (UINT8)UnitIdCount, State);
301           IDS_ERROR_TRAP;
302           break;
303         }
304         // While we are still certain we are accessing this device, remember if it is a cave device.
305         // This is found by reading EOC from the Link 1 Control Register.
306         Link1ControlRegister = CurrentPtr;
307         Link1ControlRegister.Address.Register += (HTSLAVE_LINK01_OFFSET + HTSLAVE_LINK_CONTROL_0_REG);
308         LibAmdPciReadBits (Link1ControlRegister, 6, 6, &Temp, State->ConfigHandle);
309         IsCaveDevice = ((Temp == 0) ? FALSE : TRUE);
310
311         // Attempt to write the new BUID.  Unless this chain was aleady assigned BUIDs during Init Reset,
312         // then just re-discover the chain.  Note this may be true whether the device was found at
313         // BUID zero or not.
314         IDS_HDT_CONSOLE (HT_TRACE, "Found device at depth=%d, BUID=%d.\n", Depth, CurrentPtr.Address.Device);
315         if (!IsCompatChain || !State->IsUsingRecoveryHt) {
316           IDS_HDT_CONSOLE (HT_TRACE, "Assigning device to BUID=%d.\n", CurrentBuid);
317           LibAmdPciWriteBits (CurrentPtr, 20, 16, &CurrentBuid, State->ConfigHandle);
318         }
319
320         CurrentPtr.Address.Device = CurrentBuid;
321         LibAmdPciReadBits (CurrentPtr, 20, 16, &Temp, State->ConfigHandle);
322         if (Temp != CurrentBuid) {
323           if ((Depth == 0) && IsCaveDevice) {
324             // If the chain only consists of a single cave device, that device may have retained zero
325             // for it's BUID.
326             CurrentPtr.Address.Device = 0;
327             LibAmdPciReadBits (CurrentPtr, 20, 16, &Temp, State->ConfigHandle);
328             if (Temp == 0) {
329               // Per HyperTransport specification, devices not accepting BUID reassignment hardwire BUID to zero.
330               (*State->PortList)[(State->TotalLinks * 2) + 1].Link = 0;
331               (*State->PortList)[(State->TotalLinks * 2) + 1].Pointer = CurrentPtr;
332               State->TotalLinks++;
333               Depth++;
334               // Success!
335               IDS_HDT_CONSOLE (HT_TRACE, "%s Cave left at BUID=0.\n", ((!IsCompatChain || !State->IsUsingRecoveryHt) ? "Compatible" : "Already Assigned"));
336               break;
337             } else if (Temp == CurrentBuid) {
338               // and then, there are the other kind of devices ....
339               // Restore the writable BUID field (which contains the value we just wrote) to zero.
340               Temp = 0;
341               LibAmdPciWriteBits (CurrentPtr, 20, 16, &Temp, State->ConfigHandle);
342               (*State->PortList)[(State->TotalLinks * 2) + 1].Link = 0;
343               (*State->PortList)[(State->TotalLinks * 2) + 1].Pointer = CurrentPtr;
344               State->TotalLinks++;
345               Depth++;
346               // Success!
347               IDS_HDT_CONSOLE (HT_TRACE, "Cave left at BUID=0.\n");
348               break;
349             }
350           }
351           // An error handler for this error,
352           // this often occurs in new BIOS ports and it means you need to use a Manual BUID Swap List.
353           NotifyErrorNcohDeviceFailed (Node, Link, Depth, (UINT8)CurrentBuid, State);
354           IDS_ERROR_TRAP;
355           break;
356         }
357
358         LibAmdPciReadBits (CurrentPtr, 26, 26, &Temp, State->ConfigHandle);
359         (*State->PortList)[(State->TotalLinks * 2) + 1].Link = (UINT8)Temp;
360         (*State->PortList)[(State->TotalLinks * 2) + 1].Pointer = CurrentPtr;
361
362         IDS_HDT_CONSOLE (HT_TRACE, "Device assigned.\n");
363         Depth++;
364         State->TotalLinks++;
365         CurrentBuid += UnitIdCount;
366       } else {
367         // All non-coherent devices must have a slave interface capability.
368         ASSERT (FALSE);
369         break;
370       }
371     }
372     // Provide information on automatic device results
373     NotifyInfoNcohAutoDepth (Node, Link, (Depth - 1), State);
374   }
375 }