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