1 /** @file
2 This driver installs Single Segment Pci Configuration 2 PPI
3 to provide read, write and modify access to Pci configuration space in PEI phase.
4 To follow PI specification, these services also support access to the unaligned Pci address.
5
6 Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
7 This program and the accompanying materials
8 are licensed and made available under the terms and conditions of the BSD License
9 which accompanies this distribution. The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
11
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14
15 **/
16
17 #include <PiPei.h>
18 #include <Ppi/PciCfg2.h>
19 #include <Library/BaseLib.h>
20 #include <Library/DebugLib.h>
21 #include <Library/PciLib.h>
22 #include <Library/PeimEntryPoint.h>
23 #include <Library/PeiServicesLib.h>
24 #include <IndustryStandard/Pci.h>
25
26 /**
27 Convert EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS to PCI_LIB_ADDRESS.
28
29 @param Address PCI address with EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS format.
30
31 @return PCI address with PCI_LIB_ADDRESS format.
32
33 **/
34 UINTN
PciCfgAddressConvert(EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS * Address)35 PciCfgAddressConvert (
36 EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS *Address
37 )
38 {
39 if (Address->ExtendedRegister == 0) {
40 return PCI_LIB_ADDRESS (Address->Bus, Address->Device, Address->Function, Address->Register);
41 }
42
43 return PCI_LIB_ADDRESS (Address->Bus, Address->Device, Address->Function, Address->ExtendedRegister);
44 }
45
46 /**
47 Reads from a given location in the PCI configuration space.
48
49 @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
50 @param This Pointer to local data for the interface.
51 @param Width The width of the access. Enumerated in bytes.
52 See EFI_PEI_PCI_CFG_PPI_WIDTH above.
53 @param Address The physical address of the access. The format of
54 the address is described by EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS.
55 @param Buffer A pointer to the buffer of data.
56
57 @retval EFI_SUCCESS The function completed successfully.
58 @retval EFI_INVALID_PARAMETER The invalid access width.
59
60 **/
61 EFI_STATUS
62 EFIAPI
PciCfg2Read(IN CONST EFI_PEI_SERVICES ** PeiServices,IN CONST EFI_PEI_PCI_CFG2_PPI * This,IN EFI_PEI_PCI_CFG_PPI_WIDTH Width,IN UINT64 Address,IN OUT VOID * Buffer)63 PciCfg2Read (
64 IN CONST EFI_PEI_SERVICES **PeiServices,
65 IN CONST EFI_PEI_PCI_CFG2_PPI *This,
66 IN EFI_PEI_PCI_CFG_PPI_WIDTH Width,
67 IN UINT64 Address,
68 IN OUT VOID *Buffer
69 )
70 {
71 UINTN PciLibAddress;
72
73 PciLibAddress = PciCfgAddressConvert ((EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS *) &Address);
74
75 if (Width == EfiPeiPciCfgWidthUint8) {
76 *((UINT8 *) Buffer) = PciRead8 (PciLibAddress);
77 } else if (Width == EfiPeiPciCfgWidthUint16) {
78 if ((PciLibAddress & 0x01) == 0) {
79 //
80 // Aligned Pci address access
81 //
82 WriteUnaligned16 (((UINT16 *) Buffer), PciRead16 (PciLibAddress));
83 } else {
84 //
85 // Unaligned Pci address access, break up the request into byte by byte.
86 //
87 *((UINT8 *) Buffer) = PciRead8 (PciLibAddress);
88 *((UINT8 *) Buffer + 1) = PciRead8 (PciLibAddress + 1);
89 }
90 } else if (Width == EfiPeiPciCfgWidthUint32) {
91 if ((PciLibAddress & 0x03) == 0) {
92 //
93 // Aligned Pci address access
94 //
95 WriteUnaligned32 (((UINT32 *) Buffer), PciRead32 (PciLibAddress));
96 } else if ((PciLibAddress & 0x01) == 0) {
97 //
98 // Unaligned Pci address access, break up the request into word by word.
99 //
100 WriteUnaligned16 (((UINT16 *) Buffer), PciRead16 (PciLibAddress));
101 WriteUnaligned16 (((UINT16 *) Buffer + 1), PciRead16 (PciLibAddress + 2));
102 } else {
103 //
104 // Unaligned Pci address access, break up the request into byte by byte.
105 //
106 *((UINT8 *) Buffer) = PciRead8 (PciLibAddress);
107 *((UINT8 *) Buffer + 1) = PciRead8 (PciLibAddress + 1);
108 *((UINT8 *) Buffer + 2) = PciRead8 (PciLibAddress + 2);
109 *((UINT8 *) Buffer + 3) = PciRead8 (PciLibAddress + 3);
110 }
111 } else {
112 return EFI_INVALID_PARAMETER;
113 }
114
115 return EFI_SUCCESS;
116 }
117
118 /**
119 Write to a given location in the PCI configuration space.
120
121 @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
122 @param This Pointer to local data for the interface.
123 @param Width The width of the access. Enumerated in bytes.
124 See EFI_PEI_PCI_CFG_PPI_WIDTH above.
125 @param Address The physical address of the access. The format of
126 the address is described by EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS.
127 @param Buffer A pointer to the buffer of data.
128
129 @retval EFI_SUCCESS The function completed successfully.
130 @retval EFI_INVALID_PARAMETER The invalid access width.
131
132 **/
133 EFI_STATUS
134 EFIAPI
PciCfg2Write(IN CONST EFI_PEI_SERVICES ** PeiServices,IN CONST EFI_PEI_PCI_CFG2_PPI * This,IN EFI_PEI_PCI_CFG_PPI_WIDTH Width,IN UINT64 Address,IN OUT VOID * Buffer)135 PciCfg2Write (
136 IN CONST EFI_PEI_SERVICES **PeiServices,
137 IN CONST EFI_PEI_PCI_CFG2_PPI *This,
138 IN EFI_PEI_PCI_CFG_PPI_WIDTH Width,
139 IN UINT64 Address,
140 IN OUT VOID *Buffer
141 )
142 {
143 UINTN PciLibAddress;
144
145 PciLibAddress = PciCfgAddressConvert ((EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS *) &Address);
146
147 if (Width == EfiPeiPciCfgWidthUint8) {
148 PciWrite8 (PciLibAddress, *((UINT8 *) Buffer));
149 } else if (Width == EfiPeiPciCfgWidthUint16) {
150 if ((PciLibAddress & 0x01) == 0) {
151 //
152 // Aligned Pci address access
153 //
154 PciWrite16 (PciLibAddress, ReadUnaligned16 ((UINT16 *) Buffer));
155 } else {
156 //
157 // Unaligned Pci address access, break up the request into byte by byte.
158 //
159 PciWrite8 (PciLibAddress, *((UINT8 *) Buffer));
160 PciWrite8 (PciLibAddress + 1, *((UINT8 *) Buffer + 1));
161 }
162 } else if (Width == EfiPeiPciCfgWidthUint32) {
163 if ((PciLibAddress & 0x03) == 0) {
164 //
165 // Aligned Pci address access
166 //
167 PciWrite32 (PciLibAddress, ReadUnaligned32 ((UINT32 *) Buffer));
168 } else if ((PciLibAddress & 0x01) == 0) {
169 //
170 // Unaligned Pci address access, break up the request into word by word.
171 //
172 PciWrite16 (PciLibAddress, ReadUnaligned16 ((UINT16 *) Buffer));
173 PciWrite16 (PciLibAddress + 2, ReadUnaligned16 ((UINT16 *) Buffer + 1));
174 } else {
175 //
176 // Unaligned Pci address access, break up the request into byte by byte.
177 //
178 PciWrite8 (PciLibAddress, *((UINT8 *) Buffer));
179 PciWrite8 (PciLibAddress + 1, *((UINT8 *) Buffer + 1));
180 PciWrite8 (PciLibAddress + 2, *((UINT8 *) Buffer + 2));
181 PciWrite8 (PciLibAddress + 3, *((UINT8 *) Buffer + 3));
182 }
183 } else {
184 return EFI_INVALID_PARAMETER;
185 }
186
187 return EFI_SUCCESS;
188 }
189
190
191 /**
192 This function performs a read-modify-write operation on the contents from a given
193 location in the PCI configuration space.
194
195 @param PeiServices An indirect pointer to the PEI Services Table
196 published by the PEI Foundation.
197 @param This Pointer to local data for the interface.
198 @param Width The width of the access. Enumerated in bytes. Type
199 EFI_PEI_PCI_CFG_PPI_WIDTH is defined in Read().
200 @param Address The physical address of the access.
201 @param SetBits Points to value to bitwise-OR with the read configuration value.
202 The size of the value is determined by Width.
203 @param ClearBits Points to the value to negate and bitwise-AND with the read configuration value.
204 The size of the value is determined by Width.
205
206 @retval EFI_SUCCESS The function completed successfully.
207 @retval EFI_INVALID_PARAMETER The invalid access width.
208
209 **/
210 EFI_STATUS
211 EFIAPI
PciCfg2Modify(IN CONST EFI_PEI_SERVICES ** PeiServices,IN CONST EFI_PEI_PCI_CFG2_PPI * This,IN EFI_PEI_PCI_CFG_PPI_WIDTH Width,IN UINT64 Address,IN VOID * SetBits,IN VOID * ClearBits)212 PciCfg2Modify (
213 IN CONST EFI_PEI_SERVICES **PeiServices,
214 IN CONST EFI_PEI_PCI_CFG2_PPI *This,
215 IN EFI_PEI_PCI_CFG_PPI_WIDTH Width,
216 IN UINT64 Address,
217 IN VOID *SetBits,
218 IN VOID *ClearBits
219 )
220 {
221 UINTN PciLibAddress;
222 UINT16 ClearValue16;
223 UINT16 SetValue16;
224 UINT32 ClearValue32;
225 UINT32 SetValue32;
226
227 PciLibAddress = PciCfgAddressConvert ((EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS *) &Address);
228
229 if (Width == EfiPeiPciCfgWidthUint8) {
230 PciAndThenOr8 (PciLibAddress, (UINT8) (~(*(UINT8 *) ClearBits)), *((UINT8 *) SetBits));
231 } else if (Width == EfiPeiPciCfgWidthUint16) {
232 if ((PciLibAddress & 0x01) == 0) {
233 //
234 // Aligned Pci address access
235 //
236 ClearValue16 = (UINT16) (~ReadUnaligned16 ((UINT16 *) ClearBits));
237 SetValue16 = ReadUnaligned16 ((UINT16 *) SetBits);
238 PciAndThenOr16 (PciLibAddress, ClearValue16, SetValue16);
239 } else {
240 //
241 // Unaligned Pci address access, break up the request into byte by byte.
242 //
243 PciAndThenOr8 (PciLibAddress, (UINT8) (~(*(UINT8 *) ClearBits)), *((UINT8 *) SetBits));
244 PciAndThenOr8 (PciLibAddress + 1, (UINT8) (~(*((UINT8 *) ClearBits + 1))), *((UINT8 *) SetBits + 1));
245 }
246 } else if (Width == EfiPeiPciCfgWidthUint32) {
247 if ((PciLibAddress & 0x03) == 0) {
248 //
249 // Aligned Pci address access
250 //
251 ClearValue32 = (UINT32) (~ReadUnaligned32 ((UINT32 *) ClearBits));
252 SetValue32 = ReadUnaligned32 ((UINT32 *) SetBits);
253 PciAndThenOr32 (PciLibAddress, ClearValue32, SetValue32);
254 } else if ((PciLibAddress & 0x01) == 0) {
255 //
256 // Unaligned Pci address access, break up the request into word by word.
257 //
258 ClearValue16 = (UINT16) (~ReadUnaligned16 ((UINT16 *) ClearBits));
259 SetValue16 = ReadUnaligned16 ((UINT16 *) SetBits);
260 PciAndThenOr16 (PciLibAddress, ClearValue16, SetValue16);
261
262 ClearValue16 = (UINT16) (~ReadUnaligned16 ((UINT16 *) ClearBits + 1));
263 SetValue16 = ReadUnaligned16 ((UINT16 *) SetBits + 1);
264 PciAndThenOr16 (PciLibAddress + 2, ClearValue16, SetValue16);
265 } else {
266 //
267 // Unaligned Pci address access, break up the request into byte by byte.
268 //
269 PciAndThenOr8 (PciLibAddress, (UINT8) (~(*(UINT8 *) ClearBits)), *((UINT8 *) SetBits));
270 PciAndThenOr8 (PciLibAddress + 1, (UINT8) (~(*((UINT8 *) ClearBits + 1))), *((UINT8 *) SetBits + 1));
271 PciAndThenOr8 (PciLibAddress + 2, (UINT8) (~(*((UINT8 *) ClearBits + 2))), *((UINT8 *) SetBits + 2));
272 PciAndThenOr8 (PciLibAddress + 3, (UINT8) (~(*((UINT8 *) ClearBits + 3))), *((UINT8 *) SetBits + 3));
273 }
274 } else {
275 return EFI_INVALID_PARAMETER;
276 }
277
278 return EFI_SUCCESS;
279 }
280
281 EFI_PEI_PCI_CFG2_PPI gPciCfg2Ppi = {
282 PciCfg2Read,
283 PciCfg2Write,
284 PciCfg2Modify,
285 0
286 };
287
288 EFI_PEI_PPI_DESCRIPTOR gPciCfg2PpiList = {
289 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
290 &gEfiPciCfg2PpiGuid,
291 &gPciCfg2Ppi
292 };
293
294 /**
295 Module's entry function.
296 This routine will install EFI_PEI_PCI_CFG2_PPI.
297
298 @param FileHandle Handle of the file being invoked.
299 @param PeiServices Describes the list of possible PEI Services.
300
301 @return Whether success to install service.
302 **/
303 EFI_STATUS
304 EFIAPI
PeimInitializePciCfg(IN EFI_PEI_FILE_HANDLE FileHandle,IN CONST EFI_PEI_SERVICES ** PeiServices)305 PeimInitializePciCfg (
306 IN EFI_PEI_FILE_HANDLE FileHandle,
307 IN CONST EFI_PEI_SERVICES **PeiServices
308 )
309 {
310 EFI_STATUS Status;
311
312 (**(EFI_PEI_SERVICES **)PeiServices).PciCfg = &gPciCfg2Ppi;
313 Status = PeiServicesInstallPpi (&gPciCfg2PpiList);
314 ASSERT_EFI_ERROR (Status);
315
316 return Status;
317 }
318