]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/Library/UefiPciCapPciIoLib/UefiPciCapPciIoLib.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / OvmfPkg / Library / UefiPciCapPciIoLib / UefiPciCapPciIoLib.c
CommitLineData
02b9a834
LE
1/** @file\r
2 Plug an EFI_PCI_IO_PROTOCOL backend into PciCapLib, for config space access.\r
3\r
4 Copyright (C) 2018, Red Hat, Inc.\r
5\r
b26f0cf9 6 SPDX-License-Identifier: BSD-2-Clause-Patent\r
02b9a834
LE
7**/\r
8\r
9#include <Library/MemoryAllocationLib.h>\r
10\r
11#include "UefiPciCapPciIoLib.h"\r
12\r
02b9a834
LE
13/**\r
14 Transfer bytes between the config space of a given PCI device and a memory\r
15 buffer.\r
16\r
17 ProtoDevTransferConfig() performs as few config space accesses as possible\r
18 (without attempting 64-bit wide accesses).\r
19\r
20 @param[in] PciIo The EFI_PCI_IO_PROTOCOL representation of the\r
21 PCI device.\r
22\r
23 @param[in] TransferFunction The EFI_PCI_IO_PROTOCOL_CONFIG function that\r
24 implements the transfer. The direction of the\r
25 transfer is inherent to TransferFunction.\r
26 TransferFunction() is required to return an\r
27 unspecified error if any sub-transfer within\r
28 Size bytes from ConfigOffset exceeds the config\r
29 space limit of the PCI device.\r
30\r
31 @param[in] ConfigOffset The offset in the config space of the PCI device\r
32 at which the transfer should commence.\r
33\r
34 @param[in,out] Buffer The memory buffer where the transfer should\r
35 occur.\r
36\r
37 @param[in] Size The number of bytes to transfer.\r
38\r
39 @retval EFI_SUCCESS Size bytes have been transferred between config space\r
40 and Buffer.\r
41\r
42 @return Error codes propagated from TransferFunction(). Fewer\r
43 than Size bytes may have been transferred.\r
44**/\r
45STATIC\r
46EFI_STATUS\r
47ProtoDevTransferConfig (\r
ac0a286f
MK
48 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
49 IN EFI_PCI_IO_PROTOCOL_CONFIG TransferFunction,\r
50 IN UINT16 ConfigOffset,\r
51 IN OUT UINT8 *Buffer,\r
52 IN UINT16 Size\r
02b9a834
LE
53 )\r
54{\r
55 while (Size > 0) {\r
ac0a286f
MK
56 EFI_PCI_IO_PROTOCOL_WIDTH Width;\r
57 UINT16 Count;\r
58 EFI_STATUS Status;\r
59 UINT16 Progress;\r
02b9a834
LE
60\r
61 //\r
62 // Pick the largest access size that is allowed by the remaining transfer\r
63 // Size and by the alignment of ConfigOffset.\r
64 //\r
65 // When the largest access size is available, transfer as many bytes as\r
66 // possible in one iteration of the loop. Otherwise, transfer only one\r
67 // unit, to improve the alignment.\r
68 //\r
ac0a286f 69 if ((Size >= 4) && ((ConfigOffset & 3) == 0)) {\r
02b9a834
LE
70 Width = EfiPciIoWidthUint32;\r
71 Count = Size >> Width;\r
ac0a286f 72 } else if ((Size >= 2) && ((ConfigOffset & 1) == 0)) {\r
02b9a834
LE
73 Width = EfiPciIoWidthUint16;\r
74 Count = 1;\r
75 } else {\r
76 Width = EfiPciIoWidthUint8;\r
77 Count = 1;\r
78 }\r
ac0a286f 79\r
02b9a834
LE
80 Status = TransferFunction (PciIo, Width, ConfigOffset, Count, Buffer);\r
81 if (EFI_ERROR (Status)) {\r
82 return Status;\r
83 }\r
ac0a286f 84\r
02b9a834
LE
85 Progress = Count << Width;\r
86 ConfigOffset += Progress;\r
87 Buffer += Progress;\r
88 Size -= Progress;\r
89 }\r
ac0a286f 90\r
02b9a834
LE
91 return EFI_SUCCESS;\r
92}\r
93\r
02b9a834
LE
94/**\r
95 Read the config space of a given PCI device (both normal and extended).\r
96\r
97 ProtoDevReadConfig() performs as few config space accesses as possible\r
98 (without attempting 64-bit wide accesses).\r
99\r
100 ProtoDevReadConfig() returns an unspecified error if accessing Size bytes\r
101 from SourceOffset exceeds the config space limit of the PCI device. Fewer\r
102 than Size bytes may have been read in this case.\r
103\r
104 @param[in] PciDevice Implementation-specific unique representation\r
105 of the PCI device in the PCI hierarchy.\r
106\r
107 @param[in] SourceOffset Source offset in the config space of the PCI\r
108 device to start reading from.\r
109\r
110 @param[out] DestinationBuffer Buffer to store the read data to.\r
111\r
112 @param[in] Size The number of bytes to transfer.\r
113\r
114 @retval RETURN_SUCCESS Size bytes have been transferred from config space to\r
115 DestinationBuffer.\r
116\r
117 @return Error codes propagated from\r
118 EFI_PCI_IO_PROTOCOL.Pci.Read(). Fewer than Size bytes\r
119 may have been read.\r
120**/\r
121STATIC\r
122RETURN_STATUS\r
123EFIAPI\r
124ProtoDevReadConfig (\r
ac0a286f
MK
125 IN PCI_CAP_DEV *PciDevice,\r
126 IN UINT16 SourceOffset,\r
127 OUT VOID *DestinationBuffer,\r
128 IN UINT16 Size\r
02b9a834
LE
129 )\r
130{\r
ac0a286f 131 PROTO_DEV *ProtoDev;\r
02b9a834
LE
132\r
133 ProtoDev = PROTO_DEV_FROM_PCI_CAP_DEV (PciDevice);\r
ac0a286f
MK
134 return ProtoDevTransferConfig (\r
135 ProtoDev->PciIo,\r
136 ProtoDev->PciIo->Pci.Read,\r
137 SourceOffset,\r
138 DestinationBuffer,\r
139 Size\r
140 );\r
02b9a834
LE
141}\r
142\r
02b9a834
LE
143/**\r
144 Write the config space of a given PCI device (both normal and extended).\r
145\r
146 ProtoDevWriteConfig() performs as few config space accesses as possible\r
147 (without attempting 64-bit wide accesses).\r
148\r
149 ProtoDevWriteConfig() returns an unspecified error if accessing Size bytes at\r
150 DestinationOffset exceeds the config space limit of the PCI device. Fewer\r
151 than Size bytes may have been written in this case.\r
152\r
153 @param[in] PciDevice Implementation-specific unique representation\r
154 of the PCI device in the PCI hierarchy.\r
155\r
156 @param[in] DestinationOffset Destination offset in the config space of the\r
157 PCI device to start writing at.\r
158\r
159 @param[in] SourceBuffer Buffer to read the data to be stored from.\r
160\r
161 @param[in] Size The number of bytes to transfer.\r
162\r
163 @retval RETURN_SUCCESS Size bytes have been transferred from SourceBuffer to\r
164 config space.\r
165\r
166 @return Error codes propagated from\r
167 EFI_PCI_IO_PROTOCOL.Pci.Write(). Fewer than Size\r
168 bytes may have been written.\r
169**/\r
170STATIC\r
171RETURN_STATUS\r
172EFIAPI\r
173ProtoDevWriteConfig (\r
ac0a286f
MK
174 IN PCI_CAP_DEV *PciDevice,\r
175 IN UINT16 DestinationOffset,\r
176 IN VOID *SourceBuffer,\r
177 IN UINT16 Size\r
02b9a834
LE
178 )\r
179{\r
ac0a286f 180 PROTO_DEV *ProtoDev;\r
02b9a834
LE
181\r
182 ProtoDev = PROTO_DEV_FROM_PCI_CAP_DEV (PciDevice);\r
ac0a286f
MK
183 return ProtoDevTransferConfig (\r
184 ProtoDev->PciIo,\r
185 ProtoDev->PciIo->Pci.Write,\r
186 DestinationOffset,\r
187 SourceBuffer,\r
188 Size\r
189 );\r
02b9a834
LE
190}\r
191\r
02b9a834
LE
192/**\r
193 Create a PCI_CAP_DEV object from an EFI_PCI_IO_PROTOCOL instance. The config\r
194 space accessors are based upon EFI_PCI_IO_PROTOCOL.Pci.Read() and\r
195 EFI_PCI_IO_PROTOCOL.Pci.Write().\r
196\r
197 @param[in] PciIo EFI_PCI_IO_PROTOCOL representation of the PCI device.\r
198\r
199 @param[out] PciDevice The PCI_CAP_DEV object constructed as described above.\r
200 PciDevice can be passed to the PciCapLib APIs.\r
201\r
202 @retval EFI_SUCCESS PciDevice has been constructed and output.\r
203\r
204 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.\r
205**/\r
206EFI_STATUS\r
207EFIAPI\r
208PciCapPciIoDeviceInit (\r
ac0a286f
MK
209 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
210 OUT PCI_CAP_DEV **PciDevice\r
02b9a834
LE
211 )\r
212{\r
ac0a286f 213 PROTO_DEV *ProtoDev;\r
02b9a834
LE
214\r
215 ProtoDev = AllocatePool (sizeof *ProtoDev);\r
216 if (ProtoDev == NULL) {\r
217 return EFI_OUT_OF_RESOURCES;\r
218 }\r
219\r
220 ProtoDev->Signature = PROTO_DEV_SIG;\r
221 ProtoDev->PciIo = PciIo;\r
222 ProtoDev->BaseDevice.ReadConfig = ProtoDevReadConfig;\r
223 ProtoDev->BaseDevice.WriteConfig = ProtoDevWriteConfig;\r
224\r
225 *PciDevice = &ProtoDev->BaseDevice;\r
226 return EFI_SUCCESS;\r
227}\r
228\r
02b9a834
LE
229/**\r
230 Free the resources used by PciDevice.\r
231\r
232 @param[in] PciDevice The PCI_CAP_DEV object to free, originally produced by\r
233 PciCapPciIoDeviceInit().\r
234**/\r
235VOID\r
236EFIAPI\r
237PciCapPciIoDeviceUninit (\r
ac0a286f 238 IN PCI_CAP_DEV *PciDevice\r
02b9a834
LE
239 )\r
240{\r
ac0a286f 241 PROTO_DEV *ProtoDev;\r
02b9a834
LE
242\r
243 ProtoDev = PROTO_DEV_FROM_PCI_CAP_DEV (PciDevice);\r
244 FreePool (ProtoDev);\r
245}\r