1 /** @file
2  Module produces PciCfgPpi2 on top of PciCfgPpi. It also updates the
3  PciCfg2Ppi pointer in the EFI_PEI_SERVICES upon a installation of
4  EcpPeiPciCfgPpi.
5 
6  EcpPeiPciCfgPpi is installed by a framework module which
7  produce PciCfgPpi originally. Such framework module is updated based on the
8  following rule to install EcpPeiPciCfgPpi instead of updating the PciCfg pointer
9  in the Framework PeiServicesTable:
10 
11  Search pattern:
12  	   PeiServices->PciCfg = <*>;
13  Replace pattern:
14          {
15            static EFI_PEI_PPI_DESCRIPTOR gEcpPeiPciCfgPpiList = {
16              (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
17              &gEcpPeiPciCfgPpiGuid,
18              <*>
19            };
20            (**PeiServices).InstallPpi (PeiServices, gEcpPeiPciCfgPpiList);
21          }
22 
23  In addition, the PeiServicesTable definition in PeiApi.h is updated to
24 
25  struct _EFI_PEI_SERVICES {
26    EFI_TABLE_HEADER              Hdr;
27    ...
28 
29    //
30    // Pointer to PPI interface
31    //
32  if (PI_SPECIFICATION_VERSION < 0x00010000)
33 
34    PEI_CPU_IO_PPI                 *CpuIo;
35    ECP_PEI_PCI_CFG_PPI        *PciCfg;  //Changed.
36  else
37  ...
38  endif
39 
40  };
41 
42  This change enable the detection of code segment which invokes PeiServices->PciCfg->Modify.
43  Such code causes a build break as ECP_PEI_PCI_CFG_PPI does not has "Modify" field.
44  This should be updated to a call to PeiLibPciCfgModify as shown below:
45 
46  Search pattern:
47  		*->Modify(<*>);
48  Replace pattern:
49  		PeiLibPciCfgModify(<*>);
50 
51 
52 
53 PIWG's PI specification replaces Inte's EFI Specification 1.10.
54 EFI_PEI_PCI_CFG_PPI defined in Inte's EFI Specification 1.10 is replaced by
55 EFI_PEI_PCI_CFG2_PPI in PI 1.0.
56 This module produces PciCfgPpi on top of PciCfgPpi2. This module is used on platform when both of
57 these two conditions are true:
58 1) Framework module present that produces PCI CFG PPI  AND
59 2) PI module that produces PCI CFG2 is not present
60 
61 Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
62 This program and the accompanying materials
63 are licensed and made available under the terms and conditions of the BSD License
64 which accompanies this distribution.  The full text of the license may be found at
65 http://opensource.org/licenses/bsd-license.php
66 
67 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
68 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
69 
70 **/
71 
72 #include <PiPei.h>
73 #include <Ppi/PciCfg.h>
74 #include <Ppi/PciCfg2.h>
75 #include <Ppi/EcpPciCfg.h>
76 #include <Library/DebugLib.h>
77 
78 //
79 // Function Prototypes
80 //
81 
82 /**
83   Notification service to be called when gEcpPeiPciCfgPpiGuid is installed.
84 
85   @param  PeiServices                 Indirect reference to the PEI Services Table.
86   @param  NotifyDescriptor          Address of the notification descriptor data structure. Type
87           EFI_PEI_NOTIFY_DESCRIPTOR is defined above.
88   @param  Ppi                             Address of the PPI that was installed.
89 
90   @retval   EFI_STATUS                This function will install a PPI to PPI database. The status
91                                                   code will be the code for (*PeiServices)->InstallPpi.
92 
93 **/
94 EFI_STATUS
95 EFIAPI
96 EcpPciCfgPpiNotifyCallback (
97   IN EFI_PEI_SERVICES              **PeiServices,
98   IN EFI_PEI_NOTIFY_DESCRIPTOR     *NotifyDescriptor,
99   IN VOID                          *Ppi
100   );
101 
102 //
103 // Function Prototypes
104 //
105 /**
106   Reads from a given location in the PCI configuration space.
107 
108   @param  PeiServices                   An indirect pointer to the PEI Services Table published by the PEI Foundation.
109 
110   @param  This                              Pointer to local data for the interface.
111 
112   @param  Width                           The width of the access. Enumerated in bytes.
113                                                    See EFI_PEI_PCI_CFG_PPI_WIDTH above.
114 
115   @param  Address                       The physical address of the access. The format of
116                                                   the address is described by EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS.
117 
118   @param  Buffer                           A pointer to the buffer of data..
119 
120 
121   @retval EFI_SUCCESS                 The function completed successfully.
122 
123   @retval EFI_DEVICE_ERROR        There was a problem with the transaction.
124 
125   @retval EFI_DEVICE_NOT_READY  The device is not capable of supporting the operation at this
126                                                     time.
127 
128 **/
129 EFI_STATUS
130 EFIAPI
131 PciCfg2Read (
132   IN CONST  EFI_PEI_SERVICES          **PeiServices,
133   IN CONST  EFI_PEI_PCI_CFG2_PPI      *This,
134   IN        EFI_PEI_PCI_CFG_PPI_WIDTH Width,
135   IN        UINT64                    Address,
136   IN OUT    VOID                      *Buffer
137   );
138 
139 /**
140   Write to a given location in the PCI configuration space.
141 
142   @param  PeiServices           An indirect pointer to the PEI Services Table published by the PEI Foundation.
143 
144   @param  This                  Pointer to local data for the interface.
145 
146   @param  Width                 The width of the access. Enumerated in bytes.
147                                 See EFI_PEI_PCI_CFG_PPI_WIDTH above.
148 
149   @param  Address               The physical address of the access. The format of
150                                 the address is described by EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS.
151 
152   @param  Buffer                A pointer to the buffer of data..
153 
154 
155   @retval EFI_SUCCESS           The function completed successfully.
156 
157   @retval EFI_DEVICE_ERROR      There was a problem with the transaction.
158 
159   @retval EFI_DEVICE_NOT_READY  The device is not capable of supporting the operation at this time.
160 
161 **/
162 EFI_STATUS
163 EFIAPI
164 PciCfg2Write (
165   IN CONST  EFI_PEI_SERVICES          **PeiServices,
166   IN CONST  EFI_PEI_PCI_CFG2_PPI      *This,
167   IN        EFI_PEI_PCI_CFG_PPI_WIDTH Width,
168   IN        UINT64                    Address,
169   IN OUT    VOID                      *Buffer
170   );
171 
172 /**
173   PCI read-modify-write operation.
174 
175   @param  PeiServices                     An indirect pointer to the PEI Services Table
176                                                       published by the PEI Foundation.
177 
178   @param  This                                Pointer to local data for the interface.
179 
180   @param  Width                             The width of the access. Enumerated in bytes. Type
181                                                       EFI_PEI_PCI_CFG_PPI_WIDTH is defined in Read().
182 
183   @param  Address                           The physical address of the access.
184 
185   @param  SetBits                            Points to value to bitwise-OR with the read configuration value.
186                                                       The size of the value is determined by Width.
187 
188   @param  ClearBits                         Points to the value to negate and bitwise-AND with the read configuration value.
189                                                       The size of the value is determined by Width.
190 
191 
192   @retval EFI_SUCCESS                   The function completed successfully.
193 
194   @retval EFI_DEVICE_ERROR          There was a problem with the transaction.
195 
196   @retval EFI_DEVICE_NOT_READY  The device is not capable of supporting
197                                                     the operation at this time.
198 
199 **/
200 EFI_STATUS
201 EFIAPI
202 PciCfg2Modify (
203   IN CONST  EFI_PEI_SERVICES          **PeiServices,
204   IN CONST  EFI_PEI_PCI_CFG2_PPI      *This,
205   IN        EFI_PEI_PCI_CFG_PPI_WIDTH Width,
206   IN        UINT64                    Address,
207   IN        VOID                      *SetBits,
208   IN        VOID                      *ClearBits
209   );
210 
211 //
212 // Module globals
213 //
214 EFI_PEI_NOTIFY_DESCRIPTOR mNotifyOnEcpPciCfgList = {
215   (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
216   &gEcpPeiPciCfgPpiGuid,
217   EcpPciCfgPpiNotifyCallback
218 };
219 
220 EFI_PEI_PCI_CFG2_PPI mPciCfg2Ppi = {
221   PciCfg2Read,
222   PciCfg2Write,
223   PciCfg2Modify,
224   0
225 };
226 
227 EFI_PEI_PPI_DESCRIPTOR mPpiListPciCfg2 = {
228   (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
229   &gEfiPciCfg2PpiGuid,
230   &mPciCfg2Ppi
231 };
232 
233 
234 /**
235 
236   Standard PEIM entry point.
237 
238   @param FileHandle   Handle of the file being invoked.
239   @param PeiServices  General purpose services available to every PEIM.
240 
241   @retval EFI_SUCCESS The interface could be successfully installed.
242 
243 **/
244 EFI_STATUS
245 EFIAPI
PeimInitializePciCfg2(IN EFI_PEI_FILE_HANDLE FileHandle,IN CONST EFI_PEI_SERVICES ** PeiServices)246 PeimInitializePciCfg2 (
247   IN EFI_PEI_FILE_HANDLE     FileHandle,
248   IN CONST EFI_PEI_SERVICES  **PeiServices
249   )
250 {
251   EFI_STATUS  Status;
252   VOID        *Ppi;
253 
254   //
255   // Make sure no other module has install the first instance of gEfiPciCfg2PpiGuid.
256   //
257   Status = (*PeiServices)->LocatePpi (PeiServices, &gEfiPciCfg2PpiGuid, 0, NULL, &Ppi);
258   ASSERT (Status == EFI_NOT_FOUND);
259 
260   //
261   // Register a notification for ECP PCI CFG PPI
262   //
263   Status = (*PeiServices)->NotifyPpi (PeiServices, &mNotifyOnEcpPciCfgList);
264   ASSERT_EFI_ERROR (Status);
265   return Status;
266 }
267 
268 
269 /**
270   Notification service to be called when gEcpPeiPciCfgPpiGuid is installed.
271 
272   @param  PeiServices                 Indirect reference to the PEI Services Table.
273   @param  NotifyDescriptor          Address of the notification descriptor data structure. Type
274           EFI_PEI_NOTIFY_DESCRIPTOR is defined above.
275   @param  Ppi                             Address of the PPI that was installed.
276 
277   @retval   EFI_STATUS                This function will install a PPI to PPI database. The status
278                                                   code will be the code for (*PeiServices)->InstallPpi.
279 
280 **/
281 EFI_STATUS
282 EFIAPI
EcpPciCfgPpiNotifyCallback(IN EFI_PEI_SERVICES ** PeiServices,IN EFI_PEI_NOTIFY_DESCRIPTOR * NotifyDescriptor,IN VOID * Ppi)283 EcpPciCfgPpiNotifyCallback (
284   IN EFI_PEI_SERVICES              **PeiServices,
285   IN EFI_PEI_NOTIFY_DESCRIPTOR     *NotifyDescriptor,
286   IN VOID                          *Ppi
287   )
288 {
289   //
290   // When ECP PCI CFG PPI is installed, publish the PCI CFG2 PPI in the
291   // PEI Services Table and the PPI database
292   //
293   (*PeiServices)->PciCfg = &mPciCfg2Ppi;
294   return (*PeiServices)->InstallPpi ((CONST EFI_PEI_SERVICES **)PeiServices, &mPpiListPciCfg2);
295 }
296 
297 /**
298   Reads from a given location in the PCI configuration space.
299 
300   @param  PeiServices                   An indirect pointer to the PEI Services Table published by the PEI Foundation.
301 
302   @param  This                              Pointer to local data for the interface.
303 
304   @param  Width                           The width of the access. Enumerated in bytes.
305                                                    See EFI_PEI_PCI_CFG_PPI_WIDTH above.
306 
307   @param  Address                       The physical address of the access. The format of
308                                                   the address is described by EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS.
309 
310   @param  Buffer                           A pointer to the buffer of data..
311 
312 
313   @retval EFI_SUCCESS                 The function completed successfully.
314 
315   @retval EFI_DEVICE_ERROR        There was a problem with the transaction.
316 
317   @retval EFI_DEVICE_NOT_READY  The device is not capable of supporting the operation at this
318                                                     time.
319 
320 **/
321 EFI_STATUS
322 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)323 PciCfg2Read (
324   IN CONST  EFI_PEI_SERVICES          **PeiServices,
325   IN CONST  EFI_PEI_PCI_CFG2_PPI      *This,
326   IN        EFI_PEI_PCI_CFG_PPI_WIDTH Width,
327   IN        UINT64                    Address,
328   IN OUT    VOID                      *Buffer
329   )
330 {
331   EFI_STATUS           Status;
332   EFI_PEI_PCI_CFG_PPI  *PciCfg;
333 
334   Status = (*PeiServices)->LocatePpi (
335              PeiServices,
336              &gEcpPeiPciCfgPpiGuid,
337              0,
338              NULL,
339              (VOID **)&PciCfg
340              );
341   ASSERT_EFI_ERROR (Status);
342 
343   return PciCfg->Read ((EFI_PEI_SERVICES **)PeiServices, PciCfg, Width, Address, Buffer);
344 }
345 
346 /**
347   Write to a given location in the PCI configuration space.
348 
349   @param  PeiServices                   An indirect pointer to the PEI Services Table published by the PEI Foundation.
350 
351   @param  This                              Pointer to local data for the interface.
352 
353   @param  Width                            The width of the access. Enumerated in bytes.
354                                                     See EFI_PEI_PCI_CFG_PPI_WIDTH above.
355 
356   @param  Address                         The physical address of the access. The format of
357                                                     the address is described by EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS.
358 
359   @param  Buffer                            A pointer to the buffer of data..
360 
361 
362   @retval EFI_SUCCESS                   The function completed successfully.
363 
364   @retval EFI_DEVICE_ERROR          There was a problem with the transaction.
365 
366   @retval EFI_DEVICE_NOT_READY  The device is not capable of supporting the operation at this
367                                                      time.
368 
369 **/
370 EFI_STATUS
371 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)372 PciCfg2Write (
373   IN CONST  EFI_PEI_SERVICES          **PeiServices,
374   IN CONST  EFI_PEI_PCI_CFG2_PPI      *This,
375   IN        EFI_PEI_PCI_CFG_PPI_WIDTH Width,
376   IN        UINT64                    Address,
377   IN OUT    VOID                      *Buffer
378   )
379 {
380   EFI_STATUS           Status;
381   EFI_PEI_PCI_CFG_PPI  *PciCfg;
382 
383   Status = (*PeiServices)->LocatePpi (
384              PeiServices,
385              &gEcpPeiPciCfgPpiGuid,
386              0,
387              NULL,
388              (VOID **)&PciCfg
389              );
390   ASSERT_EFI_ERROR (Status);
391 
392   return PciCfg->Write ((EFI_PEI_SERVICES **)PeiServices, PciCfg, Width, Address, Buffer);
393 }
394 
395 /**
396   PCI read-modify-write operation.
397 
398   @param  PeiServices                     An indirect pointer to the PEI Services Table
399                                                       published by the PEI Foundation.
400 
401   @param  This                                Pointer to local data for the interface.
402 
403   @param  Width                             The width of the access. Enumerated in bytes. Type
404                                                       EFI_PEI_PCI_CFG_PPI_WIDTH is defined in Read().
405 
406   @param  Address                           The physical address of the access.
407 
408   @param  SetBits                            Points to value to bitwise-OR with the read configuration value.
409                                                       The size of the value is determined by Width.
410 
411   @param  ClearBits                         Points to the value to negate and bitwise-AND with the read configuration value.
412                                                       The size of the value is determined by Width.
413 
414 
415   @retval EFI_SUCCESS                   The function completed successfully.
416 
417   @retval EFI_DEVICE_ERROR          There was a problem with the transaction.
418 
419   @retval EFI_DEVICE_NOT_READY  The device is not capable of supporting
420                                                     the operation at this time.
421 
422 **/
423 EFI_STATUS
424 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)425 PciCfg2Modify (
426   IN CONST  EFI_PEI_SERVICES          **PeiServices,
427   IN CONST  EFI_PEI_PCI_CFG2_PPI      *This,
428   IN        EFI_PEI_PCI_CFG_PPI_WIDTH Width,
429   IN        UINT64                    Address,
430   IN        VOID                      *SetBits,
431   IN        VOID                      *ClearBits
432   )
433 {
434   EFI_STATUS           Status;
435   EFI_PEI_PCI_CFG_PPI  *PciCfg;
436 
437   Status = (*PeiServices)->LocatePpi (
438              PeiServices,
439              &gEfiPciCfgPpiInServiceTableGuid,
440              0,
441              NULL,
442              (VOID **)&PciCfg
443              );
444   ASSERT_EFI_ERROR (Status);
445 
446   return PciCfg->Modify ((EFI_PEI_SERVICES **)PeiServices, PciCfg, Width, Address, *(UINTN *)SetBits, *(UINTN *)ClearBits);
447 }
448