]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Pci/PciBusDxe/PciCommand.c
MdeModulePkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / PciBusDxe / PciCommand.c
1 /** @file
2 PCI command register operations supporting functions implementation for PCI Bus module.
3
4 Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 **/
8
9 #include "PciBus.h"
10
11 /**
12 Operate the PCI register via PciIo function interface.
13
14 @param PciIoDevice Pointer to instance of PCI_IO_DEVICE.
15 @param Command Operator command.
16 @param Offset The address within the PCI configuration space for the PCI controller.
17 @param Operation Type of Operation.
18 @param PtrCommand Return buffer holding old PCI command, if operation is not EFI_SET_REGISTER.
19
20 @return Status of PciIo operation.
21
22 **/
23 EFI_STATUS
24 PciOperateRegister (
25 IN PCI_IO_DEVICE *PciIoDevice,
26 IN UINT16 Command,
27 IN UINT8 Offset,
28 IN UINT8 Operation,
29 OUT UINT16 *PtrCommand
30 )
31 {
32 UINT16 OldCommand;
33 EFI_STATUS Status;
34 EFI_PCI_IO_PROTOCOL *PciIo;
35
36 OldCommand = 0;
37 PciIo = &PciIoDevice->PciIo;
38
39 if (Operation != EFI_SET_REGISTER) {
40 Status = PciIo->Pci.Read (
41 PciIo,
42 EfiPciIoWidthUint16,
43 Offset,
44 1,
45 &OldCommand
46 );
47
48 if (Operation == EFI_GET_REGISTER) {
49 *PtrCommand = OldCommand;
50 return Status;
51 }
52 }
53
54 if (Operation == EFI_ENABLE_REGISTER) {
55 OldCommand = (UINT16) (OldCommand | Command);
56 } else if (Operation == EFI_DISABLE_REGISTER) {
57 OldCommand = (UINT16) (OldCommand & ~(Command));
58 } else {
59 OldCommand = Command;
60 }
61
62 return PciIo->Pci.Write (
63 PciIo,
64 EfiPciIoWidthUint16,
65 Offset,
66 1,
67 &OldCommand
68 );
69 }
70
71 /**
72 Check the capability supporting by given device.
73
74 @param PciIoDevice Pointer to instance of PCI_IO_DEVICE.
75
76 @retval TRUE Capability supported.
77 @retval FALSE Capability not supported.
78
79 **/
80 BOOLEAN
81 PciCapabilitySupport (
82 IN PCI_IO_DEVICE *PciIoDevice
83 )
84 {
85 if ((PciIoDevice->Pci.Hdr.Status & EFI_PCI_STATUS_CAPABILITY) != 0) {
86 return TRUE;
87 }
88
89 return FALSE;
90 }
91
92 /**
93 Locate capability register block per capability ID.
94
95 @param PciIoDevice A pointer to the PCI_IO_DEVICE.
96 @param CapId The capability ID.
97 @param Offset A pointer to the offset returned.
98 @param NextRegBlock A pointer to the next block returned.
99
100 @retval EFI_SUCCESS Successfully located capability register block.
101 @retval EFI_UNSUPPORTED Pci device does not support capability.
102 @retval EFI_NOT_FOUND Pci device support but can not find register block.
103
104 **/
105 EFI_STATUS
106 LocateCapabilityRegBlock (
107 IN PCI_IO_DEVICE *PciIoDevice,
108 IN UINT8 CapId,
109 IN OUT UINT8 *Offset,
110 OUT UINT8 *NextRegBlock OPTIONAL
111 )
112 {
113 UINT8 CapabilityPtr;
114 UINT16 CapabilityEntry;
115 UINT8 CapabilityID;
116
117 //
118 // To check the capability of this device supports
119 //
120 if (!PciCapabilitySupport (PciIoDevice)) {
121 return EFI_UNSUPPORTED;
122 }
123
124 if (*Offset != 0) {
125 CapabilityPtr = *Offset;
126 } else {
127
128 CapabilityPtr = 0;
129 if (IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {
130
131 PciIoDevice->PciIo.Pci.Read (
132 &PciIoDevice->PciIo,
133 EfiPciIoWidthUint8,
134 EFI_PCI_CARDBUS_BRIDGE_CAPABILITY_PTR,
135 1,
136 &CapabilityPtr
137 );
138 } else {
139
140 PciIoDevice->PciIo.Pci.Read (
141 &PciIoDevice->PciIo,
142 EfiPciIoWidthUint8,
143 PCI_CAPBILITY_POINTER_OFFSET,
144 1,
145 &CapabilityPtr
146 );
147 }
148 }
149
150 while ((CapabilityPtr >= 0x40) && ((CapabilityPtr & 0x03) == 0x00)) {
151 PciIoDevice->PciIo.Pci.Read (
152 &PciIoDevice->PciIo,
153 EfiPciIoWidthUint16,
154 CapabilityPtr,
155 1,
156 &CapabilityEntry
157 );
158
159 CapabilityID = (UINT8) CapabilityEntry;
160
161 if (CapabilityID == CapId) {
162 *Offset = CapabilityPtr;
163 if (NextRegBlock != NULL) {
164 *NextRegBlock = (UINT8) (CapabilityEntry >> 8);
165 }
166
167 return EFI_SUCCESS;
168 }
169
170 //
171 // Certain PCI device may incorrectly have capability pointing to itself,
172 // break to avoid dead loop.
173 //
174 if (CapabilityPtr == (UINT8) (CapabilityEntry >> 8)) {
175 break;
176 }
177
178 CapabilityPtr = (UINT8) (CapabilityEntry >> 8);
179 }
180
181 return EFI_NOT_FOUND;
182 }
183
184 /**
185 Locate PciExpress capability register block per capability ID.
186
187 @param PciIoDevice A pointer to the PCI_IO_DEVICE.
188 @param CapId The capability ID.
189 @param Offset A pointer to the offset returned.
190 @param NextRegBlock A pointer to the next block returned.
191
192 @retval EFI_SUCCESS Successfully located capability register block.
193 @retval EFI_UNSUPPORTED Pci device does not support capability.
194 @retval EFI_NOT_FOUND Pci device support but can not find register block.
195
196 **/
197 EFI_STATUS
198 LocatePciExpressCapabilityRegBlock (
199 IN PCI_IO_DEVICE *PciIoDevice,
200 IN UINT16 CapId,
201 IN OUT UINT32 *Offset,
202 OUT UINT32 *NextRegBlock OPTIONAL
203 )
204 {
205 EFI_STATUS Status;
206 UINT32 CapabilityPtr;
207 UINT32 CapabilityEntry;
208 UINT16 CapabilityID;
209
210 //
211 // To check the capability of this device supports
212 //
213 if (!PciIoDevice->IsPciExp) {
214 return EFI_UNSUPPORTED;
215 }
216
217 if (*Offset != 0) {
218 CapabilityPtr = *Offset;
219 } else {
220 CapabilityPtr = EFI_PCIE_CAPABILITY_BASE_OFFSET;
221 }
222
223 while (CapabilityPtr != 0) {
224 //
225 // Mask it to DWORD alignment per PCI spec
226 //
227 CapabilityPtr &= 0xFFC;
228 Status = PciIoDevice->PciIo.Pci.Read (
229 &PciIoDevice->PciIo,
230 EfiPciIoWidthUint32,
231 CapabilityPtr,
232 1,
233 &CapabilityEntry
234 );
235 if (EFI_ERROR (Status)) {
236 break;
237 }
238
239 CapabilityID = (UINT16) CapabilityEntry;
240
241 if (CapabilityID == CapId) {
242 *Offset = CapabilityPtr;
243 if (NextRegBlock != NULL) {
244 *NextRegBlock = (CapabilityEntry >> 20) & 0xFFF;
245 }
246
247 return EFI_SUCCESS;
248 }
249
250 CapabilityPtr = (CapabilityEntry >> 20) & 0xFFF;
251 }
252
253 return EFI_NOT_FOUND;
254 }