1 /** @file
2   This driver does SA PCI Express ACPI table initialization.
3 
4   Copyright (c) 2019 - 2020 Intel Corporation. All rights reserved. <BR>
5 
6   SPDX-License-Identifier: BSD-2-Clause-Patent
7 **/
8 
9 #include "PciExpressInit.h"
10 #include <Library/ConfigBlockLib.h>
11 
12 extern SYSTEM_AGENT_NVS_AREA_PROTOCOL   mSaNvsAreaProtocol;
13 extern SA_CONFIG_HOB                    *mSaConfigHob;
14 
15 /**
16   PCI Express Dxe Initialization.
17   Run before PCI Bus Init, where assignment of Bus, Memory,
18     and I/O Resources are assigned.
19 
20   @param[in] SaPolicy     -     SA DXE Policy protocol
21 
22   @retval EFI_SUCCESS     - Pci Express successfully started and ready to be used
23 **/
24 EFI_STATUS
25 PciExpressInit (
26   IN SA_POLICY_PROTOCOL *SaPolicy
27   )
28 {
29   EFI_STATUS                                    Status;
30   PCIE_DXE_CONFIG                               *PcieDxeConfig;
31   MSR_BROADWELL_PKG_CST_CONFIG_CONTROL_REGISTER Msr;
32 
33   Status = GetConfigBlock ((VOID *) SaPolicy, &gPcieDxeConfigGuid, (VOID *)&PcieDxeConfig);
34   ASSERT_EFI_ERROR (Status);
35 
36 
37   Msr.Uint64 = AsmReadMsr64 (MSR_BROADWELL_PKG_CST_CONFIG_CONTROL);
38   mSaNvsAreaProtocol.Area->PackageCstateLimit  = (UINT8) Msr.Bits.Limit;
39 
40   mSaNvsAreaProtocol.Area->PwrDnBundlesGlobalEnable  = 0;
41 
42   if (mSaConfigHob != NULL) {
43     mSaNvsAreaProtocol.Area->Peg0PowerDownUnusedBundles  = mSaConfigHob->PowerDownUnusedBundles[0];
44     mSaNvsAreaProtocol.Area->Peg1PowerDownUnusedBundles  = mSaConfigHob->PowerDownUnusedBundles[1];
45     mSaNvsAreaProtocol.Area->Peg2PowerDownUnusedBundles  = mSaConfigHob->PowerDownUnusedBundles[2];
46     if (SA_PEG_MAX_FUN > 3) {
47       mSaNvsAreaProtocol.Area->Peg3PowerDownUnusedBundles  = mSaConfigHob->PowerDownUnusedBundles[3];
48     }
49   }
50   ///
51   /// LTR/OBFF
52   ///
53   mSaNvsAreaProtocol.Area->Peg0LtrEnable                = PcieDxeConfig->PegPwrOpt[0].LtrEnable;
54   mSaNvsAreaProtocol.Area->Peg0ObffEnable               = PcieDxeConfig->PegPwrOpt[0].ObffEnable;
55   mSaNvsAreaProtocol.Area->Peg1LtrEnable                = PcieDxeConfig->PegPwrOpt[1].LtrEnable;
56   mSaNvsAreaProtocol.Area->Peg1ObffEnable               = PcieDxeConfig->PegPwrOpt[1].ObffEnable;
57   mSaNvsAreaProtocol.Area->Peg2LtrEnable                = PcieDxeConfig->PegPwrOpt[2].LtrEnable;
58   mSaNvsAreaProtocol.Area->Peg2ObffEnable               = PcieDxeConfig->PegPwrOpt[2].ObffEnable;
59   mSaNvsAreaProtocol.Area->PegLtrMaxSnoopLatency        = LTR_MAX_SNOOP_LATENCY_VALUE;
60   mSaNvsAreaProtocol.Area->PegLtrMaxNoSnoopLatency      = LTR_MAX_NON_SNOOP_LATENCY_VALUE;
61 
62   return EFI_SUCCESS;
63 }
64 
65 /**
66   Find the Offset to a given Capabilities ID
67   CAPID list:
68     0x01 = PCI Power Management Interface
69     0x04 = Slot Identification
70     0x05 = MSI Capability
71     0x10 = PCI Express Capability
72 
73   @param[in] Segment   -   Pci Segment Number
74   @param[in] Bus       -   Pci Bus Number
75   @param[in] Device    -   Pci Device Number
76   @param[in] Function  -   Pci Function Number
77   @param[in] CapId     -   CAPID to search for
78 
79   @retval 0       - CAPID not found
80   @retval Other   - CAPID found, Offset of desired CAPID
81 **/
82 UINT32
83 PcieFindCapId (
84   IN UINT8   Segment,
85   IN UINT8   Bus,
86   IN UINT8   Device,
87   IN UINT8   Function,
88   IN UINT8   CapId
89   )
90 {
91   UINT64 DeviceBaseAddress;
92   UINT8  CapHeader;
93 
94   ///
95   /// Always start at Offset 0x34
96   ///
97   DeviceBaseAddress = PCI_SEGMENT_LIB_ADDRESS (Segment, Bus, Device, Function, 0);
98   CapHeader         = PciSegmentRead8 (DeviceBaseAddress + PCI_CAPBILITY_POINTER_OFFSET);
99   if (CapHeader == 0xFF) {
100     return 0;
101   }
102 
103   while (CapHeader != 0) {
104     ///
105     /// Bottom 2 bits of the pointers are reserved per PCI Local Bus Spec 2.2
106     ///
107     CapHeader &= ~(BIT1 + BIT0);
108     ///
109     /// Search for desired CapID
110     ///
111     if (PciSegmentRead8 (DeviceBaseAddress + CapHeader) == CapId) {
112       return CapHeader;
113     }
114 
115     CapHeader = PciSegmentRead8 (DeviceBaseAddress + CapHeader + 1);
116   }
117 
118   return 0;
119 }
120 
121 /**
122   Search and return the offset of desired Pci Express Capability ID
123   CAPID list:
124     0x0001 = Advanced Error Rreporting Capability
125     0x0002 = Virtual Channel Capability
126     0x0003 = Device Serial Number Capability
127     0x0004 = Power Budgeting Capability
128 
129   @param[in] Segment   -   Pci Segment Number
130   @param[in] Bus       -   Pci Bus Number
131   @param[in] Device    -   Pci Device Number
132   @param[in] Function  -   Pci Function Number
133   @param[in] CapId     -   Extended CAPID to search for
134 
135   @retval 0       - CAPID not found
136   @retval Other   - CAPID found, Offset of desired CAPID
137 **/
138 UINT32
139 PcieFindExtendedCapId (
140   IN UINT8   Segment,
141   IN UINT8   Bus,
142   IN UINT8   Device,
143   IN UINT8   Function,
144   IN UINT16  CapId
145   )
146 {
147   UINT64  DeviceBaseAddress;
148   UINT16  CapHeaderOffset;
149   UINT16  CapHeaderId;
150 
151   ///
152   /// Start to search at Offset 0x100
153   /// Get Capability Header
154   ///
155   DeviceBaseAddress = PCI_SEGMENT_LIB_ADDRESS (Segment, Bus, Device, Function, 0);
156   CapHeaderId     = 0;
157   CapHeaderOffset = 0x100;
158 
159   while (CapHeaderOffset != 0 && CapHeaderId != 0xFFFF) {
160     ///
161     /// Search for desired CapID
162     ///
163     CapHeaderId = PciSegmentRead16 (DeviceBaseAddress + CapHeaderOffset);
164     if (CapHeaderId == CapId) {
165       return CapHeaderOffset;
166     }
167 
168     CapHeaderOffset = (PciSegmentRead16 (DeviceBaseAddress + CapHeaderOffset + 2) >> 4);
169   }
170 
171   return 0;
172 }
173