5 * Non-Coherent Discovery Routines.
7 * Contains routines for enumerating and initializing non-coherent devices.
9 * @xrefitem bom "File Content Label" "Release Content"
11 * @e sub-project: HyperTransport
12 * @e \$Revision: 56279 $ @e \$Date: 2011-07-11 13:11:28 -0600 (Mon, 11 Jul 2011) $
16 *****************************************************************************
18 * Copyright (C) 2012 Advanced Micro Devices, Inc.
19 * All rights reserved.
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.
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.
43 * ***************************************************************************
48 *----------------------------------------------------------------------------
51 *----------------------------------------------------------------------------
61 #include "htInterface.h"
64 #include "htFeatNoncoherent.h"
65 #include "htFeatOptimization.h"
70 #define FILECODE PROC_HT_FEATURES_HTFEATNONCOHERENT_FILECODE
71 /*----------------------------------------------------------------------------
72 * DEFINITIONS AND MACROS
74 *----------------------------------------------------------------------------
76 #define NO_DEVICE 0xFFFFFFFFull
78 /*----------------------------------------------------------------------------
79 * TYPEDEFS AND STRUCTURES
81 *----------------------------------------------------------------------------
84 /*----------------------------------------------------------------------------
85 * PROTOTYPES OF LOCAL FUNCTIONS
87 *----------------------------------------------------------------------------
90 /*----------------------------------------------------------------------------
93 *----------------------------------------------------------------------------
96 /*----------------------------------------------------------------------------
99 *----------------------------------------------------------------------------
102 /***************************************************************************
103 *** Non-coherent init code ***
105 ***************************************************************************/
106 /*----------------------------------------------------------------------------------------*/
108 * Process a non-coherent Link.
110 * @HtFeatMethod{::F_PROCESS_LINK}
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.
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
124 IN BOOLEAN IsCompatChain,
125 IN OUT STATE_DATA *State
134 PCI_ADDR Link1ControlRegister;
136 BUID_SWAP_LIST *SwapPtr;
138 BOOLEAN IsCaveDevice;
140 ASSERT ((Node < MAX_NODES) && (Link < State->Nb->MaxLinks));
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
148 NotifyErrorNcohBusMaxExceed (Node, Link, State->AutoBusCurrent, State);
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.
157 NotifyErrorNcohCfgMapExceed (Node, Link, State);
161 SecBus = State->AutoBusCurrent;
162 SubBus = SecBus + State->HtBlock->AutoBusIncrement - 1;
163 State->AutoBusCurrent = State->AutoBusCurrent + State->HtBlock->AutoBusIncrement;
166 State->Nb->SetConfigAddrMap (State->UsedCfgMapEntries, SecBus, SubBus, Node, Link, State, State->Nb);
167 State->UsedCfgMapEntries++;
169 if (State->HtInterface->GetManualBuidSwapList (Node, Link, &SwapPtr, State)) {
170 // Manual non-coherent BUID assignment
171 AGESA_TESTPOINT (TpProcHtManualNc, State->ConfigHandle);
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.
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);
188 // All non-coherent devices must have a slave interface capability.
195 // Build chain of devices. Do this even if Recovery HT assign BUIDs for this chain.
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.
202 (*State->PortList)[(State->TotalLinks * 2)].Type = PORTLIST_TYPE_CPU;
203 (*State->PortList)[(State->TotalLinks * 2)].Link = Link;
205 // Fill in the host side port. Link and base pointer can be deduced from the upstream link's
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;
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;
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;
223 // All non-coherent devices must have a slave interface capability.
228 // Bit 6 indicates whether orientation override is desired.
229 // Bit 7 indicates the upstream Link if overriding.
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;
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;
242 (*State->PortList)[(State->TotalLinks * 2) + 1].Link = LastLink;
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" : ""));
255 CurrentPtr.AddressValue = MAKE_SBDFO (0, SecBus, 0, 0, 0);
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.
268 // No more devices found.
273 ASSERT (State->TotalLinks < MAX_PLATFORM_LINKS);
275 (*State->PortList)[(State->TotalLinks * 2)].NodeID = Node;
277 (*State->PortList)[(State->TotalLinks * 2)].Type = PORTLIST_TYPE_CPU;
278 (*State->PortList)[(State->TotalLinks * 2)].Link = Link;
280 // Fill in the host side port. Link and base pointer can be deduced from the upstream link's
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;
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;
294 if (DoesDeviceHaveHtSubtypeCap (CurrentPtr, HT_SLAVE_CAPABILITY, &CurrentPtr, State)) {
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);
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);
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
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);
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
326 CurrentPtr.Address.Device = 0;
327 LibAmdPciReadBits (CurrentPtr, 20, 16, &Temp, State->ConfigHandle);
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;
335 IDS_HDT_CONSOLE (HT_TRACE, "%s Cave left at BUID=0.\n", ((!IsCompatChain || !State->IsUsingRecoveryHt) ? "Compatible" : "Already Assigned"));
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.
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;
347 IDS_HDT_CONSOLE (HT_TRACE, "Cave left at BUID=0.\n");
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);
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;
362 IDS_HDT_CONSOLE (HT_TRACE, "Device assigned.\n");
365 CurrentBuid += UnitIdCount;
367 // All non-coherent devices must have a slave interface capability.
372 // Provide information on automatic device results
373 NotifyInfoNcohAutoDepth (Node, Link, (Depth - 1), State);