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