Add parameter checking for PCI IO protocol according to UEFI spec.
[people/mcb30/edk2.git] / edk2 / IntelFrameworkModulePkg / Bus / Pci / PciBusDxe / PciIo.c
1 /**@file\r
2   Implement all interfaces for EFI_PCI_IO_PROTOCOL.\r
3   \r
4 Copyright (c) 2006 - 2008, Intel Corporation                                                         \r
5 All rights reserved. This program and the accompanying materials                          \r
6 are licensed and made available under the terms and conditions of the BSD License         \r
7 which accompanies this distribution.  The full text of the license may be found at        \r
8 http://opensource.org/licenses/bsd-license.php                                            \r
9                                                                                           \r
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             \r
12 \r
13 **/\r
14 \r
15 \r
16 #include "pcibus.h"\r
17 \r
18 //\r
19 // Internal use only\r
20 //\r
21 STATIC\r
22 EFI_STATUS\r
23 ReportErrorStatusCode (\r
24   IN PCI_IO_DEVICE               *PciIoDevice,\r
25   IN EFI_STATUS_CODE_VALUE       Code\r
26   );\r
27 \r
28 //\r
29 // PCI I/O Support Function Prototypes\r
30 //\r
31 //\r
32 //\r
33 // Pci Io Protocol Interface\r
34 //\r
35 static EFI_PCI_IO_PROTOCOL  PciIoInterface = {\r
36   PciIoPollMem,\r
37   PciIoPollIo,\r
38   {\r
39     PciIoMemRead,\r
40     PciIoMemWrite\r
41   },\r
42   {\r
43     PciIoIoRead,\r
44     PciIoIoWrite\r
45   },\r
46   {\r
47     PciIoConfigRead,\r
48     PciIoConfigWrite\r
49   },\r
50   PciIoCopyMem,\r
51   PciIoMap,\r
52   PciIoUnmap,\r
53   PciIoAllocateBuffer,\r
54   PciIoFreeBuffer,\r
55   PciIoFlush,\r
56   PciIoGetLocation,\r
57   PciIoAttributes,\r
58   PciIoGetBarAttributes,\r
59   PciIoSetBarAttributes,\r
60   0,\r
61   NULL\r
62 };\r
63 \r
64 /**\r
65   report a error Status code of PCI bus driver controller\r
66   \r
67   @param PciIoDevice Pci device instance\r
68   @param Code        status code\r
69 **/\r
70 STATIC\r
71 EFI_STATUS\r
72 ReportErrorStatusCode (\r
73   IN PCI_IO_DEVICE               *PciIoDevice,\r
74   IN EFI_STATUS_CODE_VALUE       Code\r
75   )\r
76 {\r
77   return REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
78           EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
79           Code,\r
80           PciIoDevice->DevicePath\r
81           );\r
82 }\r
83 \r
84 /**\r
85   Initializes a PCI I/O Instance\r
86   \r
87   @param PciIoDevice  Pci device instance\r
88   \r
89   @retval EFI_SUCCESS  Success operation\r
90 **/\r
91 EFI_STATUS\r
92 InitializePciIoInstance (\r
93   PCI_IO_DEVICE  *PciIoDevice\r
94   )\r
95 {\r
96   CopyMem (&PciIoDevice->PciIo, &PciIoInterface, sizeof (EFI_PCI_IO_PROTOCOL));\r
97   return EFI_SUCCESS;\r
98 }\r
99 \r
100 /**\r
101   Verifies access to a PCI Base Address Register (BAR)\r
102   \r
103   @param PciIoDevice  Pci device instance\r
104   @param BarIndex     The BAR index of the standard PCI Configuration header to use as the\r
105                       base address for the memory or I/O operation to perform.                    \r
106   @param Type         Operation type could be memory or I/O\r
107   @param Width        Signifies the width of the memory or I/O operations.\r
108   @param Count        The number of memory or I/O operations to perform.\r
109   @param Offset       The offset within the PCI configuration space for the PCI controller.\r
110   \r
111   @retval EFI_INVALID_PARAMETER Invalid Width/BarIndex or Bar type.\r
112   @retval EFI_SUCCESS           Success Operation.\r
113 **/\r
114 EFI_STATUS\r
115 PciIoVerifyBarAccess (\r
116   PCI_IO_DEVICE                   *PciIoDevice,\r
117   UINT8                           BarIndex,\r
118   PCI_BAR_TYPE                    Type,\r
119   IN EFI_PCI_IO_PROTOCOL_WIDTH    Width,\r
120   IN UINTN                        Count,\r
121   UINT64                          *Offset\r
122   )\r
123 {\r
124   if (Width < 0 || Width >= EfiPciIoWidthMaximum) {\r
125     return EFI_INVALID_PARAMETER;\r
126   }\r
127 \r
128   if (BarIndex == EFI_PCI_IO_PASS_THROUGH_BAR) {\r
129     return EFI_SUCCESS;\r
130   }\r
131 \r
132   //\r
133   // BarIndex 0-5 is legal\r
134   //\r
135   if (BarIndex >= PCI_MAX_BAR) {\r
136     return EFI_INVALID_PARAMETER;\r
137   }\r
138 \r
139   if (!CheckBarType (PciIoDevice, BarIndex, Type)) {\r
140     return EFI_INVALID_PARAMETER;\r
141   }\r
142 \r
143   //\r
144   // If Width is EfiPciIoWidthFifoUintX then convert to EfiPciIoWidthUintX\r
145   // If Width is EfiPciIoWidthFillUintX then convert to EfiPciIoWidthUintX\r
146   //\r
147   if (Width >= EfiPciWidthFifoUint8 && Width <= EfiPciWidthFifoUint64) {\r
148     Count = 1;\r
149   }\r
150 \r
151   Width = (EFI_PCI_IO_PROTOCOL_WIDTH) (Width & 0x03);\r
152 \r
153   if ((*Offset + Count * (UINTN)(1 << Width)) - 1 >= PciIoDevice->PciBar[BarIndex].Length) {\r
154     return EFI_INVALID_PARAMETER;\r
155   }\r
156 \r
157   *Offset = *Offset + PciIoDevice->PciBar[BarIndex].BaseAddress;\r
158 \r
159   return EFI_SUCCESS;\r
160 }\r
161 \r
162 /**\r
163   Verifies access to a PCI Config Header\r
164   \r
165   @param PciIoDevice  Pci device instance\r
166   @param Width        Signifies the width of the memory or I/O operations.\r
167   @param Count        The number of memory or I/O operations to perform.\r
168   @param Offset       The offset within the PCI configuration space for the PCI controller.\r
169 \r
170   @retval EFI_INVALID_PARAMETER  Invalid Width\r
171   @retval EFI_UNSUPPORTED        Offset overflow\r
172   @retval EFI_SUCCESS            Success operation\r
173 **/\r
174 EFI_STATUS\r
175 PciIoVerifyConfigAccess (\r
176   PCI_IO_DEVICE                 *PciIoDevice,\r
177   IN EFI_PCI_IO_PROTOCOL_WIDTH  Width,\r
178   IN UINTN                      Count,\r
179   IN UINT64                     *Offset\r
180   )\r
181 {\r
182   UINT64  ExtendOffset;\r
183 \r
184   if (Width < 0 || Width >= EfiPciIoWidthMaximum) {\r
185     return EFI_INVALID_PARAMETER;\r
186   }\r
187 \r
188   //\r
189   // If Width is EfiPciIoWidthFillUintX then convert to EfiPciIoWidthUintX\r
190   //\r
191   Width = (EFI_PCI_IO_PROTOCOL_WIDTH) (Width & 0x03);\r
192 \r
193   if (PciIoDevice->IsPciExp) {\r
194     if ((*Offset + Count * (UINTN)(1 << Width)) - 1 >= PCI_EXP_MAX_CONFIG_OFFSET) {\r
195       return EFI_UNSUPPORTED;\r
196     }\r
197 \r
198     ExtendOffset  = LShiftU64 (*Offset, 32);\r
199     *Offset       = EFI_PCI_ADDRESS (PciIoDevice->BusNumber, PciIoDevice->DeviceNumber, PciIoDevice->FunctionNumber, 0);\r
200     *Offset       = (*Offset) | ExtendOffset;\r
201 \r
202   } else {\r
203     if ((*Offset + Count * (UINTN)(1 << Width)) - 1 >= PCI_MAX_CONFIG_OFFSET) {\r
204       return EFI_UNSUPPORTED;\r
205     }\r
206 \r
207     *Offset = EFI_PCI_ADDRESS (PciIoDevice->BusNumber, PciIoDevice->DeviceNumber, PciIoDevice->FunctionNumber, *Offset);\r
208   }\r
209 \r
210   return EFI_SUCCESS;\r
211 }\r
212 \r
213 /**\r
214   Reads from the I/O space of a PCI Root Bridge. Returns when either the polling exit criteria is\r
215   satisfied or after a defined duration.\r
216   \r
217   @param This       Pointer to protocol instance of EFI_PCI_IO_PROTOCOL\r
218   @param Width      Signifies the width of the memory or I/O operations.\r
219   @param BarIndex   The BAR index of the standard PCI Configuration header to use as the\r
220                     base address for the memory or I/O operation to perform. \r
221   @param Offset     The offset within the PCI configuration space for the PCI controller.\r
222   @param Mask       Mask used for the polling criteria.\r
223   @param Value      The comparison value used for the polling exit criteria.\r
224   @param Delay      The number of 100 ns units to poll.\r
225   @param Result     Pointer to the last value read from the memory location.\r
226   \r
227   @retval EFI_SUCCESS           The last data returned from the access matched the poll exit criteria.\r
228   @retval EFI_TIMEOUT           Delay expired before a match occurred.\r
229   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.\r
230   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
231 **/\r
232 EFI_STATUS\r
233 EFIAPI\r
234 PciIoPollMem (\r
235   IN  EFI_PCI_IO_PROTOCOL        *This,\r
236   IN  EFI_PCI_IO_PROTOCOL_WIDTH  Width,\r
237   IN  UINT8                      BarIndex,\r
238   IN  UINT64                     Offset,\r
239   IN  UINT64                     Mask,\r
240   IN  UINT64                     Value,\r
241   IN  UINT64                     Delay,\r
242   OUT UINT64                     *Result\r
243   )\r
244 {\r
245   EFI_STATUS    Status;\r
246   PCI_IO_DEVICE *PciIoDevice;\r
247 \r
248   PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);\r
249 \r
250   if (Width < 0 || Width >= EfiPciIoWidthMaximum) {\r
251     return EFI_INVALID_PARAMETER;\r
252   }\r
253 \r
254   Status = PciIoVerifyBarAccess (PciIoDevice, BarIndex, PciBarTypeMem, Width, 1, &Offset);\r
255   if (EFI_ERROR (Status)) {\r
256     return EFI_UNSUPPORTED;\r
257   }\r
258 \r
259   if (Width > EfiPciIoWidthUint64) {\r
260     return EFI_INVALID_PARAMETER;\r
261   }\r
262 \r
263   Status = PciIoDevice->PciRootBridgeIo->PollMem (\r
264                                           PciIoDevice->PciRootBridgeIo,\r
265                                           (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,\r
266                                           Offset,\r
267                                           Mask,\r
268                                           Value,\r
269                                           Delay,\r
270                                           Result\r
271                                           );\r
272 \r
273   if (EFI_ERROR (Status)) {\r
274     ReportErrorStatusCode (PciIoDevice, EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR);\r
275   }\r
276 \r
277   return Status;\r
278 }\r
279 \r
280 /**                                                                 \r
281   Reads from the I/O space of a PCI Root Bridge. Returns when either the polling exit criteria is\r
282   satisfied or after a defined duration.\r
283           \r
284   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL.\r
285   @param  Width                 Signifies the width of the memory or I/O operations.\r
286   @param  Address               The base address of the memory or I/O operations.  \r
287   @param  Mask                  Mask used for the polling criteria.\r
288   @param  Value                 The comparison value used for the polling exit criteria.\r
289   @param  Delay                 The number of 100 ns units to poll.\r
290   @param  Result                Pointer to the last value read from the memory location.\r
291                                 \r
292   @retval EFI_SUCCESS           The last data returned from the access matched the poll exit criteria.\r
293   @retval EFI_TIMEOUT           Delay expired before a match occurred.\r
294   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.\r
295   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
296                                    \r
297 **/\r
298 EFI_STATUS\r
299 EFIAPI\r
300 PciIoPollIo (\r
301   IN  EFI_PCI_IO_PROTOCOL        *This,\r
302   IN  EFI_PCI_IO_PROTOCOL_WIDTH  Width,\r
303   IN  UINT8                      BarIndex,\r
304   IN  UINT64                     Offset,\r
305   IN  UINT64                     Mask,\r
306   IN  UINT64                     Value,\r
307   IN  UINT64                     Delay,\r
308   OUT UINT64                     *Result\r
309   )\r
310 {\r
311   EFI_STATUS    Status;\r
312   PCI_IO_DEVICE *PciIoDevice;\r
313 \r
314   PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);\r
315 \r
316   if (Width < 0 || Width > EfiPciIoWidthUint64) {\r
317     return EFI_INVALID_PARAMETER;\r
318   }\r
319 \r
320   Status = PciIoVerifyBarAccess (PciIoDevice, BarIndex, PciBarTypeIo, Width, 1, &Offset);\r
321   if (EFI_ERROR (Status)) {\r
322     return EFI_UNSUPPORTED;\r
323   }\r
324 \r
325   Status = PciIoDevice->PciRootBridgeIo->PollIo (\r
326                                           PciIoDevice->PciRootBridgeIo,\r
327                                           (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,\r
328                                           Offset,\r
329                                           Mask,\r
330                                           Value,\r
331                                           Delay,\r
332                                           Result\r
333                                           );\r
334 \r
335   if (EFI_ERROR (Status)) {\r
336     ReportErrorStatusCode (PciIoDevice, EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR);\r
337   }\r
338 \r
339   return Status;\r
340 }\r
341 \r
342 /**                                                                 \r
343   Enable a PCI driver to access PCI controller registers in the PCI memory or I/O space.\r
344           \r
345   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
346   @param  Width                 Signifies the width of the memory or I/O operations.\r
347   @param  BarIndex              The BAR index of the standard PCI Configuration header to use as the\r
348                                 base address for the memory or I/O operation to perform.                    \r
349   @param  Offset                The offset within the selected BAR to start the memory or I/O operation.                                \r
350   @param  Count                 The number of memory or I/O operations to perform.\r
351   @param  Buffer                For read operations, the destination buffer to store the results. For write\r
352                                 operations, the source buffer to write data from.                          \r
353   \r
354   @retval EFI_SUCCESS           The data was read from or written to the PCI controller.\r
355   @retval EFI_UNSUPPORTED       BarIndex not valid for this PCI controller.\r
356   @retval EFI_UNSUPPORTED       The address range specified by Offset, Width, and Count is not\r
357                                 valid for the PCI BAR specified by BarIndex.                  \r
358   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.\r
359   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
360                                    \r
361 **/\r
362 EFI_STATUS\r
363 EFIAPI\r
364 PciIoMemRead (\r
365   IN     EFI_PCI_IO_PROTOCOL        *This,\r
366   IN     EFI_PCI_IO_PROTOCOL_WIDTH  Width,\r
367   IN     UINT8                      BarIndex,\r
368   IN     UINT64                     Offset,\r
369   IN     UINTN                      Count,\r
370   IN OUT VOID                       *Buffer\r
371   )\r
372 {\r
373   EFI_STATUS    Status;\r
374   PCI_IO_DEVICE *PciIoDevice;\r
375 \r
376   PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);\r
377 \r
378   if (Width < 0 || Width >= EfiPciIoWidthMaximum) {\r
379     return EFI_INVALID_PARAMETER;\r
380   }\r
381 \r
382   if (Buffer == NULL) {\r
383     return EFI_INVALID_PARAMETER;\r
384   }\r
385 \r
386   Status = PciIoVerifyBarAccess (PciIoDevice, BarIndex, PciBarTypeMem, Width, Count, &Offset);\r
387   if (EFI_ERROR (Status)) {\r
388     return EFI_UNSUPPORTED;\r
389   }\r
390 \r
391   Status = PciIoDevice->PciRootBridgeIo->Mem.Read (\r
392                                               PciIoDevice->PciRootBridgeIo,\r
393                                               (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,\r
394                                               Offset,\r
395                                               Count,\r
396                                               Buffer\r
397                                               );\r
398 \r
399   if (EFI_ERROR (Status)) {\r
400     ReportErrorStatusCode (PciIoDevice, EFI_IO_BUS_PCI | EFI_IOB_EC_READ_ERROR);\r
401   }\r
402 \r
403   return Status;\r
404 }\r
405 \r
406 /**                                                                 \r
407   Enable a PCI driver to access PCI controller registers in the PCI memory or I/O space.\r
408           \r
409   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
410   @param  Width                 Signifies the width of the memory or I/O operations.\r
411   @param  BarIndex              The BAR index of the standard PCI Configuration header to use as the\r
412                                 base address for the memory or I/O operation to perform.                    \r
413   @param  Offset                The offset within the selected BAR to start the memory or I/O operation.                                \r
414   @param  Count                 The number of memory or I/O operations to perform.\r
415   @param  Buffer                For read operations, the destination buffer to store the results. For write\r
416                                 operations, the source buffer to write data from.                          \r
417   \r
418   @retval EFI_SUCCESS           The data was read from or written to the PCI controller.\r
419   @retval EFI_UNSUPPORTED       BarIndex not valid for this PCI controller.\r
420   @retval EFI_UNSUPPORTED       The address range specified by Offset, Width, and Count is not\r
421                                 valid for the PCI BAR specified by BarIndex.                  \r
422   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.\r
423   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
424                                    \r
425 **/\r
426 EFI_STATUS\r
427 EFIAPI\r
428 PciIoMemWrite (\r
429   IN     EFI_PCI_IO_PROTOCOL        *This,\r
430   IN     EFI_PCI_IO_PROTOCOL_WIDTH  Width,\r
431   IN     UINT8                      BarIndex,\r
432   IN     UINT64                     Offset,\r
433   IN     UINTN                      Count,\r
434   IN OUT VOID                       *Buffer\r
435   )\r
436 {\r
437   EFI_STATUS    Status;\r
438   PCI_IO_DEVICE *PciIoDevice;\r
439 \r
440   PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);\r
441 \r
442   if (Width < 0 || Width >= EfiPciIoWidthMaximum) {\r
443     return EFI_INVALID_PARAMETER;\r
444   }\r
445 \r
446   if (Buffer == NULL) {\r
447     return EFI_INVALID_PARAMETER;\r
448   }\r
449 \r
450   Status = PciIoVerifyBarAccess (PciIoDevice, BarIndex, PciBarTypeMem, Width, Count, &Offset);\r
451   if (EFI_ERROR (Status)) {\r
452     return EFI_UNSUPPORTED;\r
453   }\r
454 \r
455   Status = PciIoDevice->PciRootBridgeIo->Mem.Write (\r
456                                               PciIoDevice->PciRootBridgeIo,\r
457                                               (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,\r
458                                               Offset,\r
459                                               Count,\r
460                                               Buffer\r
461                                               );\r
462 \r
463   if (EFI_ERROR (Status)) {\r
464     ReportErrorStatusCode (PciIoDevice, EFI_IO_BUS_PCI | EFI_IOB_EC_WRITE_ERROR);\r
465   }\r
466 \r
467   return Status;\r
468 }\r
469 \r
470 /**                                                                 \r
471   Enable a PCI driver to access PCI controller registers in the PCI memory or I/O space.\r
472           \r
473   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
474   @param  Width                 Signifies the width of the memory or I/O operations.\r
475   @param  BarIndex              The BAR index of the standard PCI Configuration header to use as the\r
476                                 base address for the memory or I/O operation to perform.                    \r
477   @param  Offset                The offset within the selected BAR to start the memory or I/O operation.                                \r
478   @param  Count                 The number of memory or I/O operations to perform.\r
479   @param  Buffer                For read operations, the destination buffer to store the results. For write\r
480                                 operations, the source buffer to write data from.                          \r
481   \r
482   @retval EFI_SUCCESS           The data was read from or written to the PCI controller.\r
483   @retval EFI_UNSUPPORTED       BarIndex not valid for this PCI controller.\r
484   @retval EFI_UNSUPPORTED       The address range specified by Offset, Width, and Count is not\r
485                                 valid for the PCI BAR specified by BarIndex.                  \r
486   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.\r
487   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
488                                    \r
489 **/\r
490 EFI_STATUS\r
491 EFIAPI\r
492 PciIoIoRead (\r
493   IN     EFI_PCI_IO_PROTOCOL        *This,\r
494   IN     EFI_PCI_IO_PROTOCOL_WIDTH  Width,\r
495   IN     UINT8                      BarIndex,\r
496   IN     UINT64                     Offset,\r
497   IN     UINTN                      Count,\r
498   IN OUT VOID                       *Buffer\r
499   )\r
500 {\r
501   EFI_STATUS    Status;\r
502   PCI_IO_DEVICE *PciIoDevice;\r
503 \r
504   PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);\r
505 \r
506   if (Width < 0 || Width >= EfiPciIoWidthMaximum) {\r
507     return EFI_INVALID_PARAMETER;\r
508   }\r
509 \r
510   if (Buffer == NULL) {\r
511     return EFI_INVALID_PARAMETER;\r
512   }\r
513 \r
514   Status = PciIoVerifyBarAccess (PciIoDevice, BarIndex, PciBarTypeIo, Width, Count, &Offset);\r
515   if (EFI_ERROR (Status)) {\r
516     return EFI_UNSUPPORTED;\r
517   }\r
518 \r
519   Status = PciIoDevice->PciRootBridgeIo->Io.Read (\r
520                                               PciIoDevice->PciRootBridgeIo,\r
521                                               (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,\r
522                                               Offset,\r
523                                               Count,\r
524                                               Buffer\r
525                                               );\r
526 \r
527   if (EFI_ERROR (Status)) {\r
528     ReportErrorStatusCode (PciIoDevice, EFI_IO_BUS_PCI | EFI_IOB_EC_READ_ERROR);\r
529   }\r
530 \r
531   return Status;\r
532 }\r
533 \r
534 /**                                                                 \r
535   Enable a PCI driver to access PCI controller registers in the PCI memory or I/O space.\r
536           \r
537   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
538   @param  Width                 Signifies the width of the memory or I/O operations.\r
539   @param  BarIndex              The BAR index of the standard PCI Configuration header to use as the\r
540                                 base address for the memory or I/O operation to perform.                    \r
541   @param  Offset                The offset within the selected BAR to start the memory or I/O operation.                                \r
542   @param  Count                 The number of memory or I/O operations to perform.\r
543   @param  Buffer                For read operations, the destination buffer to store the results. For write\r
544                                 operations, the source buffer to write data from.                          \r
545   \r
546   @retval EFI_SUCCESS           The data was read from or written to the PCI controller.\r
547   @retval EFI_UNSUPPORTED       BarIndex not valid for this PCI controller.\r
548   @retval EFI_UNSUPPORTED       The address range specified by Offset, Width, and Count is not\r
549                                 valid for the PCI BAR specified by BarIndex.                  \r
550   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.\r
551   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
552                                    \r
553 **/\r
554 EFI_STATUS\r
555 EFIAPI\r
556 PciIoIoWrite (\r
557   IN     EFI_PCI_IO_PROTOCOL        *This,\r
558   IN     EFI_PCI_IO_PROTOCOL_WIDTH  Width,\r
559   IN     UINT8                      BarIndex,\r
560   IN     UINT64                     Offset,\r
561   IN     UINTN                      Count,\r
562   IN OUT VOID                       *Buffer\r
563   )\r
564 {\r
565   EFI_STATUS    Status;\r
566   PCI_IO_DEVICE *PciIoDevice;\r
567 \r
568   PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);\r
569 \r
570   if (Width < 0 || Width >= EfiPciIoWidthMaximum) {\r
571     return EFI_INVALID_PARAMETER;\r
572   }\r
573 \r
574   if (Buffer == NULL) {\r
575     return EFI_INVALID_PARAMETER;\r
576   }\r
577 \r
578   Status = PciIoVerifyBarAccess (PciIoDevice, BarIndex, PciBarTypeIo, Width, Count, &Offset);\r
579   if (EFI_ERROR (Status)) {\r
580     return EFI_UNSUPPORTED;\r
581   }\r
582 \r
583   Status = PciIoDevice->PciRootBridgeIo->Io.Write (\r
584                                               PciIoDevice->PciRootBridgeIo,\r
585                                               (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,\r
586                                               Offset,\r
587                                               Count,\r
588                                               Buffer\r
589                                               );\r
590 \r
591   if (EFI_ERROR (Status)) {\r
592     ReportErrorStatusCode (PciIoDevice, EFI_IO_BUS_PCI | EFI_IOB_EC_WRITE_ERROR);\r
593   }\r
594 \r
595   return Status;\r
596 }\r
597 \r
598 /**                                                                 \r
599   Enable a PCI driver to access PCI controller registers in PCI configuration space.\r
600             \r
601   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.  \r
602   @param  Width                 Signifies the width of the memory operations.\r
603   @param  Offset                The offset within the PCI configuration space for the PCI controller.\r
604   @param  Count                 The number of PCI configuration operations to perform.\r
605   @param  Buffer                For read operations, the destination buffer to store the results. For write\r
606                                 operations, the source buffer to write data from.\r
607   \r
608                                   \r
609   @retval EFI_SUCCESS           The data was read from or written to the PCI controller.\r
610   @retval EFI_UNSUPPORTED       The address range specified by Offset, Width, and Count is not\r
611                                 valid for the PCI configuration header of the PCI controller.\r
612   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.                                 \r
613   @retval EFI_INVALID_PARAMETER Buffer is NULL or Width is invalid.                                \r
614                                      \r
615 **/\r
616 EFI_STATUS\r
617 EFIAPI\r
618 PciIoConfigRead (\r
619   IN     EFI_PCI_IO_PROTOCOL        *This,\r
620   IN     EFI_PCI_IO_PROTOCOL_WIDTH  Width,\r
621   IN     UINT32                     Offset,\r
622   IN     UINTN                      Count,\r
623   IN OUT VOID                       *Buffer\r
624   )\r
625 {\r
626   EFI_STATUS    Status;\r
627   PCI_IO_DEVICE *PciIoDevice;\r
628   UINT64        Address;\r
629 \r
630   PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);\r
631 \r
632   Address     = Offset;\r
633   Status      = PciIoVerifyConfigAccess (PciIoDevice, Width, Count, &Address);\r
634   if (EFI_ERROR (Status)) {\r
635     return Status;\r
636   }\r
637 \r
638   Status = PciIoDevice->PciRootBridgeIo->Pci.Read (\r
639                                               PciIoDevice->PciRootBridgeIo,\r
640                                               (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,\r
641                                               Address,\r
642                                               Count,\r
643                                               Buffer\r
644                                               );\r
645 \r
646   if (EFI_ERROR (Status)) {\r
647     ReportErrorStatusCode (PciIoDevice, EFI_IO_BUS_PCI | EFI_IOB_EC_READ_ERROR);\r
648   }\r
649 \r
650   return Status;\r
651 }\r
652 \r
653 /**                                                                 \r
654   Enable a PCI driver to access PCI controller registers in PCI configuration space.\r
655             \r
656   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.  \r
657   @param  Width                 Signifies the width of the memory operations.\r
658   @param  Offset                The offset within the PCI configuration space for the PCI controller.\r
659   @param  Count                 The number of PCI configuration operations to perform.\r
660   @param  Buffer                For read operations, the destination buffer to store the results. For write\r
661                                 operations, the source buffer to write data from.\r
662   \r
663                                   \r
664   @retval EFI_SUCCESS           The data was read from or written to the PCI controller.\r
665   @retval EFI_UNSUPPORTED       The address range specified by Offset, Width, and Count is not\r
666                                 valid for the PCI configuration header of the PCI controller.\r
667   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.                                 \r
668   @retval EFI_INVALID_PARAMETER Buffer is NULL or Width is invalid.                                \r
669                                      \r
670 **/\r
671 EFI_STATUS\r
672 EFIAPI\r
673 PciIoConfigWrite (\r
674   IN     EFI_PCI_IO_PROTOCOL        *This,\r
675   IN     EFI_PCI_IO_PROTOCOL_WIDTH  Width,\r
676   IN     UINT32                     Offset,\r
677   IN     UINTN                      Count,\r
678   IN OUT VOID                       *Buffer\r
679   )\r
680 {\r
681   EFI_STATUS    Status;\r
682   PCI_IO_DEVICE *PciIoDevice;\r
683   UINT64        Address;\r
684 \r
685   PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);\r
686 \r
687   Address     = Offset;\r
688   Status      = PciIoVerifyConfigAccess (PciIoDevice, Width, Count, &Address);\r
689   if (EFI_ERROR (Status)) {\r
690     return Status;\r
691   }\r
692 \r
693   Status = PciIoDevice->PciRootBridgeIo->Pci.Write (\r
694                                               PciIoDevice->PciRootBridgeIo,\r
695                                               (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,\r
696                                               Address,\r
697                                               Count,\r
698                                               Buffer\r
699                                               );\r
700 \r
701   if (EFI_ERROR (Status)) {\r
702     ReportErrorStatusCode (PciIoDevice, EFI_IO_BUS_PCI | EFI_IOB_EC_WRITE_ERROR);\r
703   }\r
704 \r
705   return Status;\r
706 }\r
707 \r
708 /**                                                                 \r
709   Enables a PCI driver to copy one region of PCI memory space to another region of PCI\r
710   memory space.\r
711             \r
712   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
713   @param  Width                 Signifies the width of the memory operations.\r
714   @param  DestBarIndex          The BAR index in the standard PCI Configuration header to use as the\r
715                                 base address for the memory operation to perform.                   \r
716   @param  DestOffset            The destination offset within the BAR specified by DestBarIndex to\r
717                                 start the memory writes for the copy operation.                   \r
718   @param  SrcBarIndex           The BAR index in the standard PCI Configuration header to use as the\r
719                                 base address for the memory operation to perform.                   \r
720   @param  SrcOffset             The source offset within the BAR specified by SrcBarIndex to start\r
721                                 the memory reads for the copy operation.                          \r
722   @param  Count                 The number of memory operations to perform. Bytes moved is Width\r
723                                 size * Count, starting at DestOffset and SrcOffset.             \r
724                                 \r
725   @retval EFI_SUCCESS           The data was copied from one memory region to another memory region.\r
726   @retval EFI_UNSUPPORTED       DestBarIndex not valid for this PCI controller.\r
727   @retval EFI_UNSUPPORTED       SrcBarIndex not valid for this PCI controller.\r
728   @retval EFI_UNSUPPORTED       The address range specified by DestOffset, Width, and Count\r
729                                 is not valid for the PCI BAR specified by DestBarIndex.    \r
730   @retval EFI_UNSUPPORTED       The address range specified by SrcOffset, Width, and Count is\r
731                                 not valid for the PCI BAR specified by SrcBarIndex.          \r
732   @retval EFI_INVALID_PARAMETER Width is invalid.\r
733   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.\r
734                                    \r
735 **/\r
736 EFI_STATUS\r
737 EFIAPI\r
738 PciIoCopyMem (\r
739   IN EFI_PCI_IO_PROTOCOL              *This,\r
740   IN     EFI_PCI_IO_PROTOCOL_WIDTH    Width,\r
741   IN     UINT8                        DestBarIndex,\r
742   IN     UINT64                       DestOffset,\r
743   IN     UINT8                        SrcBarIndex,\r
744   IN     UINT64                       SrcOffset,\r
745   IN     UINTN                        Count\r
746   )\r
747 {\r
748   EFI_STATUS    Status;\r
749   PCI_IO_DEVICE *PciIoDevice;\r
750 \r
751   PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);\r
752 \r
753   if (Width < 0 || Width >= EfiPciIoWidthMaximum) {\r
754     return EFI_INVALID_PARAMETER;\r
755   }\r
756 \r
757   if (Width == EfiPciIoWidthFifoUint8  ||\r
758       Width == EfiPciIoWidthFifoUint16 ||\r
759       Width == EfiPciIoWidthFifoUint32 ||\r
760       Width == EfiPciIoWidthFifoUint64 ||\r
761       Width == EfiPciIoWidthFillUint8  ||\r
762       Width == EfiPciIoWidthFillUint16 ||\r
763       Width == EfiPciIoWidthFillUint32 ||\r
764       Width == EfiPciIoWidthFillUint64) {\r
765     return EFI_INVALID_PARAMETER;\r
766   }\r
767 \r
768   Status = PciIoVerifyBarAccess (PciIoDevice, DestBarIndex, PciBarTypeMem, Width, Count, &DestOffset);\r
769   if (EFI_ERROR (Status)) {\r
770     return EFI_UNSUPPORTED;\r
771   }\r
772 \r
773   Status = PciIoVerifyBarAccess (PciIoDevice, SrcBarIndex, PciBarTypeMem, Width, Count, &SrcOffset);\r
774   if (EFI_ERROR (Status)) {\r
775     return EFI_UNSUPPORTED;\r
776   }\r
777 \r
778   Status = PciIoDevice->PciRootBridgeIo->CopyMem (\r
779                                           PciIoDevice->PciRootBridgeIo,\r
780                                           (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,\r
781                                           DestOffset,\r
782                                           SrcOffset,\r
783                                           Count\r
784                                           );\r
785 \r
786   if (EFI_ERROR (Status)) {\r
787     ReportErrorStatusCode (PciIoDevice, EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR);\r
788   }\r
789 \r
790   return Status;\r
791 }\r
792 \r
793 /**                                                                 \r
794   Provides the PCI controller-Cspecific addresses needed to access system memory.\r
795             \r
796   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
797   @param  Operation             Indicates if the bus master is going to read or write to system memory.\r
798   @param  HostAddress           The system memory address to map to the PCI controller.\r
799   @param  NumberOfBytes         On input the number of bytes to map. On output the number of bytes\r
800                                 that were mapped.                                                 \r
801   @param  DeviceAddress         The resulting map address for the bus master PCI controller to use to\r
802                                 access the hosts HostAddress.                                        \r
803   @param  Mapping               A resulting value to pass to Unmap().\r
804                                   \r
805   @retval EFI_SUCCESS           The range was mapped for the returned NumberOfBytes.\r
806   @retval EFI_UNSUPPORTED       The HostAddress cannot be mapped as a common buffer.                                \r
807   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
808   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.\r
809   @retval EFI_DEVICE_ERROR      The system hardware could not map the requested address.\r
810                                    \r
811 **/\r
812 EFI_STATUS\r
813 EFIAPI\r
814 PciIoMap (\r
815   IN     EFI_PCI_IO_PROTOCOL            *This,\r
816   IN     EFI_PCI_IO_PROTOCOL_OPERATION  Operation,\r
817   IN     VOID                           *HostAddress,\r
818   IN OUT UINTN                          *NumberOfBytes,\r
819   OUT    EFI_PHYSICAL_ADDRESS           *DeviceAddress,\r
820   OUT    VOID                           **Mapping\r
821   )\r
822 {\r
823   EFI_STATUS    Status;\r
824   PCI_IO_DEVICE *PciIoDevice;\r
825 \r
826   PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);\r
827 \r
828   if (Operation < 0 || Operation >= EfiPciIoOperationMaximum) {\r
829     return EFI_INVALID_PARAMETER;\r
830   }\r
831 \r
832   if (HostAddress == NULL || NumberOfBytes == NULL || DeviceAddress == NULL || Mapping == NULL) {\r
833     return EFI_INVALID_PARAMETER;\r
834   }\r
835 \r
836   if (PciIoDevice->Attributes & EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE) {\r
837     Operation = (EFI_PCI_IO_PROTOCOL_OPERATION) (Operation + EfiPciOperationBusMasterRead64);\r
838   }\r
839 \r
840   Status = PciIoDevice->PciRootBridgeIo->Map (\r
841                                           PciIoDevice->PciRootBridgeIo,\r
842                                           (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION) Operation,\r
843                                           HostAddress,\r
844                                           NumberOfBytes,\r
845                                           DeviceAddress,\r
846                                           Mapping\r
847                                           );\r
848 \r
849   if (EFI_ERROR (Status)) {\r
850     ReportErrorStatusCode (PciIoDevice, EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR);\r
851   }\r
852 \r
853   return Status;\r
854 }\r
855 \r
856 /**                                                                 \r
857   Completes the Map() operation and releases any corresponding resources.\r
858             \r
859   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.                                      \r
860   @param  Mapping               The mapping value returned from Map().\r
861                                   \r
862   @retval EFI_SUCCESS           The range was unmapped.\r
863   @retval EFI_DEVICE_ERROR      The data was not committed to the target system memory.\r
864                                    \r
865 **/\r
866 EFI_STATUS\r
867 EFIAPI\r
868 PciIoUnmap (\r
869   IN  EFI_PCI_IO_PROTOCOL  *This,\r
870   IN  VOID                 *Mapping\r
871   )\r
872 {\r
873   EFI_STATUS    Status;\r
874   PCI_IO_DEVICE *PciIoDevice;\r
875 \r
876   PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);\r
877 \r
878   Status = PciIoDevice->PciRootBridgeIo->Unmap (\r
879                                           PciIoDevice->PciRootBridgeIo,\r
880                                           Mapping\r
881                                           );\r
882 \r
883   if (EFI_ERROR (Status)) {\r
884     ReportErrorStatusCode (PciIoDevice, EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR);\r
885   }\r
886 \r
887   return Status;\r
888 }\r
889 \r
890 /**                                                                 \r
891   Allocates pages that are suitable for an EfiPciIoOperationBusMasterCommonBuffer\r
892   mapping.                                                                       \r
893             \r
894   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
895   @param  Type                  This parameter is not used and must be ignored.\r
896   @param  MemoryType            The type of memory to allocate, EfiBootServicesData or\r
897                                 EfiRuntimeServicesData.                               \r
898   @param  Pages                 The number of pages to allocate.                                \r
899   @param  HostAddress           A pointer to store the base system memory address of the\r
900                                 allocated range.                                        \r
901   @param  Attributes            The requested bit mask of attributes for the allocated range.\r
902                                   \r
903   @retval EFI_SUCCESS           The requested memory pages were allocated.\r
904   @retval EFI_UNSUPPORTED       Attributes is unsupported. The only legal attribute bits are\r
905                                 MEMORY_WRITE_COMBINE and MEMORY_CACHED.                     \r
906   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
907   @retval EFI_OUT_OF_RESOURCES  The memory pages could not be allocated.  \r
908                                    \r
909 **/\r
910 EFI_STATUS\r
911 EFIAPI\r
912 PciIoAllocateBuffer (\r
913   IN  EFI_PCI_IO_PROTOCOL   *This,\r
914   IN  EFI_ALLOCATE_TYPE     Type,\r
915   IN  EFI_MEMORY_TYPE       MemoryType,\r
916   IN  UINTN                 Pages,\r
917   OUT VOID                  **HostAddress,\r
918   IN  UINT64                Attributes\r
919   )\r
920 {\r
921   EFI_STATUS    Status;\r
922   PCI_IO_DEVICE *PciIoDevice;\r
923 \r
924   if (Attributes &\r
925       (~(EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE | EFI_PCI_ATTRIBUTE_MEMORY_CACHED))) {\r
926     return EFI_UNSUPPORTED;\r
927   }\r
928 \r
929   PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);\r
930 \r
931   if (PciIoDevice->Attributes & EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE) {\r
932     Attributes |= EFI_PCI_ATTRIBUTE_DUAL_ADDRESS_CYCLE;\r
933   }\r
934 \r
935   Status = PciIoDevice->PciRootBridgeIo->AllocateBuffer (\r
936                                           PciIoDevice->PciRootBridgeIo,\r
937                                           Type,\r
938                                           MemoryType,\r
939                                           Pages,\r
940                                           HostAddress,\r
941                                           Attributes\r
942                                           );\r
943 \r
944   if (EFI_ERROR (Status)) {\r
945     ReportErrorStatusCode (PciIoDevice, EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR);\r
946   }\r
947 \r
948   return Status;\r
949 }\r
950 \r
951 /**                                                                 \r
952   Frees memory that was allocated with AllocateBuffer().\r
953             \r
954   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.  \r
955   @param  Pages                 The number of pages to free.                                \r
956   @param  HostAddress           The base system memory address of the allocated range.                                    \r
957                                   \r
958   @retval EFI_SUCCESS           The requested memory pages were freed.\r
959   @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages\r
960                                 was not allocated with AllocateBuffer().\r
961                                      \r
962 **/\r
963 EFI_STATUS\r
964 EFIAPI\r
965 PciIoFreeBuffer (\r
966   IN  EFI_PCI_IO_PROTOCOL   *This,\r
967   IN  UINTN                 Pages,\r
968   IN  VOID                  *HostAddress\r
969   )\r
970 {\r
971   EFI_STATUS    Status;\r
972   PCI_IO_DEVICE *PciIoDevice;\r
973 \r
974   PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);\r
975 \r
976   Status = PciIoDevice->PciRootBridgeIo->FreeBuffer (\r
977                                           PciIoDevice->PciRootBridgeIo,\r
978                                           Pages,\r
979                                           HostAddress\r
980                                           );\r
981 \r
982   if (EFI_ERROR (Status)) {\r
983     ReportErrorStatusCode (PciIoDevice, EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR);\r
984   }\r
985 \r
986   return Status;\r
987 }\r
988 \r
989 /**                                                                 \r
990   Flushes all PCI posted write transactions from a PCI host bridge to system memory.\r
991             \r
992   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.  \r
993                                   \r
994   @retval EFI_SUCCESS           The PCI posted write transactions were flushed from the PCI host\r
995                                 bridge to system memory.                                        \r
996   @retval EFI_DEVICE_ERROR      The PCI posted write transactions were not flushed from the PCI\r
997                                 host bridge due to a hardware error.                           \r
998                                      \r
999 **/\r
1000 EFI_STATUS\r
1001 EFIAPI\r
1002 PciIoFlush (\r
1003   IN  EFI_PCI_IO_PROTOCOL  *This\r
1004   )\r
1005 {\r
1006   EFI_STATUS    Status;\r
1007   PCI_IO_DEVICE *PciIoDevice;\r
1008 \r
1009   PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);\r
1010 \r
1011   Status = PciIoDevice->PciRootBridgeIo->Flush (\r
1012                                            PciIoDevice->PciRootBridgeIo\r
1013                                            );\r
1014   if (EFI_ERROR (Status)) {\r
1015     ReportErrorStatusCode (PciIoDevice, EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR);\r
1016   }\r
1017 \r
1018   return Status;\r
1019 }\r
1020 \r
1021 /**                                                                 \r
1022   Retrieves this PCI controller's current PCI bus number, device number, and function number.\r
1023             \r
1024   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.  \r
1025   @param  SegmentNumber         The PCI controller's current PCI segment number.\r
1026   @param  BusNumber             The PCI controller's current PCI bus number.\r
1027   @param  DeviceNumber          The PCI controller's current PCI device number.\r
1028   @param  FunctionNumber        The PCI controller's current PCI function number.\r
1029                                   \r
1030   @retval EFI_SUCCESS           The PCI controller location was returned.                                                       \r
1031   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.                              \r
1032                                      \r
1033 **/\r
1034 EFI_STATUS\r
1035 EFIAPI\r
1036 PciIoGetLocation (\r
1037   IN  EFI_PCI_IO_PROTOCOL  *This,\r
1038   OUT UINTN                *Segment,\r
1039   OUT UINTN                *Bus,\r
1040   OUT UINTN                *Device,\r
1041   OUT UINTN                *Function\r
1042   )\r
1043 {\r
1044   PCI_IO_DEVICE *PciIoDevice;\r
1045 \r
1046   PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);\r
1047 \r
1048   if (Segment == NULL || Bus == NULL || Device == NULL || Function == NULL) {\r
1049     return EFI_INVALID_PARAMETER;\r
1050   }\r
1051 \r
1052   *Segment  = PciIoDevice->PciRootBridgeIo->SegmentNumber;\r
1053   *Bus      = PciIoDevice->BusNumber;\r
1054   *Device   = PciIoDevice->DeviceNumber;\r
1055   *Function = PciIoDevice->FunctionNumber;\r
1056 \r
1057   return EFI_SUCCESS;\r
1058 }\r
1059 \r
1060 /**\r
1061   Check BAR type for PCI resource.\r
1062   \r
1063   @param PciIoDevice   PCI device instance\r
1064   @param BarIndex      The BAR index of the standard PCI Configuration header to use as the\r
1065                        base address for the memory or I/O operation to perform.                    \r
1066   @param BarType       Memory or I/O\r
1067   \r
1068   @return whether Pci device's bar type is same with input BarType.\r
1069 **/\r
1070 BOOLEAN\r
1071 CheckBarType (\r
1072   IN PCI_IO_DEVICE       *PciIoDevice,\r
1073   UINT8                  BarIndex,\r
1074   PCI_BAR_TYPE           BarType\r
1075   )\r
1076 {\r
1077   switch (BarType) {\r
1078 \r
1079   case PciBarTypeMem:\r
1080 \r
1081     if (PciIoDevice->PciBar[BarIndex].BarType != PciBarTypeMem32  &&\r
1082         PciIoDevice->PciBar[BarIndex].BarType != PciBarTypePMem32 &&\r
1083         PciIoDevice->PciBar[BarIndex].BarType != PciBarTypePMem64 &&\r
1084         PciIoDevice->PciBar[BarIndex].BarType != PciBarTypeMem64    ) {\r
1085       return FALSE;\r
1086     }\r
1087 \r
1088     return TRUE;\r
1089 \r
1090   case PciBarTypeIo:\r
1091     if (PciIoDevice->PciBar[BarIndex].BarType != PciBarTypeIo32 &&\r
1092         PciIoDevice->PciBar[BarIndex].BarType != PciBarTypeIo16){\r
1093       return FALSE;\r
1094     }\r
1095 \r
1096     return TRUE;\r
1097 \r
1098   default:\r
1099     break;\r
1100   }\r
1101 \r
1102   return FALSE;\r
1103 }\r
1104 \r
1105 /**\r
1106   Set/Disable new attributes to a Root Bridge\r
1107   \r
1108   @param  PciIoDevice  Pci device instance\r
1109   @param  Attributes   New attribute want to be set\r
1110   @param  Operation    Set or Disable\r
1111   \r
1112   @retval  EFI_UNSUPPORTED  If root bridge does not support change attribute\r
1113   @retval  EFI_SUCCESS      Success operation.\r
1114 **/\r
1115 EFI_STATUS\r
1116 ModifyRootBridgeAttributes (\r
1117   IN  PCI_IO_DEVICE                            *PciIoDevice,\r
1118   IN  UINT64                                   Attributes,\r
1119   IN  EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION  Operation\r
1120   )\r
1121 {\r
1122   UINT64      PciRootBridgeSupports;\r
1123   UINT64      PciRootBridgeAttributes;\r
1124   UINT64      NewPciRootBridgeAttributes;\r
1125   EFI_STATUS  Status;\r
1126 \r
1127   //\r
1128   // Get the current attributes of this PCI device's PCI Root Bridge\r
1129   //\r
1130   Status = PciIoDevice->PciRootBridgeIo->GetAttributes (\r
1131                                           PciIoDevice->PciRootBridgeIo,\r
1132                                           &PciRootBridgeSupports,\r
1133                                           &PciRootBridgeAttributes\r
1134                                           );\r
1135   if (EFI_ERROR (Status)) {\r
1136     return EFI_UNSUPPORTED;\r
1137   }\r
1138   \r
1139   //\r
1140   // Record the new attribute of the Root Bridge\r
1141   //\r
1142   if (Operation == EfiPciIoAttributeOperationEnable) {\r
1143     NewPciRootBridgeAttributes = PciRootBridgeAttributes | Attributes;\r
1144   } else {\r
1145     NewPciRootBridgeAttributes = PciRootBridgeAttributes & (~Attributes);\r
1146   }\r
1147  \r
1148   //\r
1149   // Call the PCI Root Bridge to attempt to modify the attributes\r
1150   //\r
1151   if (NewPciRootBridgeAttributes ^ PciRootBridgeAttributes) {\r
1152 \r
1153     Status = PciIoDevice->PciRootBridgeIo->SetAttributes (\r
1154                                             PciIoDevice->PciRootBridgeIo,\r
1155                                             NewPciRootBridgeAttributes,\r
1156                                             NULL,\r
1157                                             NULL\r
1158                                             );\r
1159     if (EFI_ERROR (Status)) {\r
1160       //\r
1161       // The PCI Root Bridge could not modify the attributes, so return the error.\r
1162       //\r
1163       return EFI_UNSUPPORTED;\r
1164     }\r
1165   }\r
1166     \r
1167   //\r
1168   // Also update the attributes for this Root Bridge structure\r
1169   //\r
1170   PciIoDevice->Attributes = NewPciRootBridgeAttributes;\r
1171   return EFI_SUCCESS;\r
1172 \r
1173 }\r
1174 \r
1175 /**\r
1176   Check whether this device can be enable/disable to snoop\r
1177   \r
1178   @param PciIoDevice  Pci device instance\r
1179   @param Operation    Enable/Disable\r
1180   \r
1181   @retval EFI_UNSUPPORTED  Pci device is not GFX device or not support snoop\r
1182   @retval EFI_SUCCESS      Snoop can be supported.\r
1183 **/\r
1184 EFI_STATUS\r
1185 SupportPaletteSnoopAttributes (\r
1186   IN  PCI_IO_DEVICE                            *PciIoDevice,\r
1187   IN  EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION  Operation\r
1188   )\r
1189 {\r
1190   PCI_IO_DEVICE *Temp;\r
1191   UINT16        VGACommand;\r
1192 \r
1193   //\r
1194   // Snoop attribute can be only modified by GFX\r
1195   //\r
1196   if (!IS_PCI_GFX (&PciIoDevice->Pci)) {\r
1197     return EFI_UNSUPPORTED;\r
1198   }\r
1199 \r
1200   //\r
1201   // Get the boot VGA on the same segement\r
1202   //\r
1203   Temp = ActiveVGADeviceOnTheSameSegment (PciIoDevice);\r
1204 \r
1205   if (!Temp) {\r
1206     //\r
1207     // If there is no VGA device on the segement, set\r
1208     // this graphics card to decode the palette range\r
1209     //\r
1210     return EFI_SUCCESS;\r
1211   }\r
1212   \r
1213   //\r
1214   // Check these two agents are on the same path\r
1215   //\r
1216   if (!PciDevicesOnTheSamePath (Temp, PciIoDevice)) {\r
1217     //\r
1218     // they are not on the same path, so snoop can be enabled or disabled\r
1219     //\r
1220     return EFI_SUCCESS;\r
1221   }\r
1222   //\r
1223   // Check if they are on the same bus\r
1224   //\r
1225   if (Temp->Parent == PciIoDevice->Parent) {\r
1226 \r
1227     PciReadCommandRegister (Temp, &VGACommand);\r
1228 \r
1229     //\r
1230     // If they are on the same bus, either one can\r
1231     // be set to snoop, the other set to decode\r
1232     //\r
1233     if (VGACommand & EFI_PCI_COMMAND_VGA_PALETTE_SNOOP) {\r
1234       //\r
1235       // VGA has set to snoop, so GFX can be only set to disable snoop\r
1236       //\r
1237       if (Operation == EfiPciIoAttributeOperationEnable) {\r
1238         return EFI_UNSUPPORTED;\r
1239       }\r
1240     } else {\r
1241       //\r
1242       // VGA has disabled to snoop, so GFX can be only enabled\r
1243       //\r
1244       if (Operation == EfiPciIoAttributeOperationDisable) {\r
1245         return EFI_UNSUPPORTED;\r
1246       }\r
1247     }\r
1248 \r
1249     return EFI_SUCCESS;\r
1250   }\r
1251   \r
1252   //\r
1253   // If they are on  the same path but on the different bus\r
1254   // The first agent is set to snoop, the second one set to\r
1255   // decode\r
1256   //\r
1257             \r
1258   if (Temp->BusNumber < PciIoDevice->BusNumber) {\r
1259     //\r
1260     // GFX should be set to decode\r
1261     //\r
1262     if (Operation == EfiPciIoAttributeOperationDisable) {\r
1263       PciEnableCommandRegister (Temp, EFI_PCI_COMMAND_VGA_PALETTE_SNOOP);\r
1264       Temp->Attributes |= EFI_PCI_COMMAND_VGA_PALETTE_SNOOP;\r
1265     } else {\r
1266       return EFI_UNSUPPORTED;\r
1267     }\r
1268 \r
1269   } else {\r
1270     //\r
1271     // GFX should be set to snoop\r
1272     //\r
1273     if (Operation == EfiPciIoAttributeOperationEnable) {\r
1274       PciDisableCommandRegister (Temp, EFI_PCI_COMMAND_VGA_PALETTE_SNOOP);\r
1275       Temp->Attributes &= (~EFI_PCI_COMMAND_VGA_PALETTE_SNOOP);\r
1276     } else {\r
1277       return EFI_UNSUPPORTED;\r
1278     }\r
1279 \r
1280   }\r
1281 \r
1282   return EFI_SUCCESS;\r
1283 }\r
1284 \r
1285 /**                                                                 \r
1286   Performs an operation on the attributes that this PCI controller supports. The operations include\r
1287   getting the set of supported attributes, retrieving the current attributes, setting the current  \r
1288   attributes, enabling attributes, and disabling attributes.                                       \r
1289             \r
1290   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.  \r
1291   @param  Operation             The operation to perform on the attributes for this PCI controller.\r
1292   @param  Attributes            The mask of attributes that are used for Set, Enable, and Disable\r
1293                                 operations.                                                      \r
1294   @param  Result                A pointer to the result mask of attributes that are returned for the Get\r
1295                                 and Supported operations.                                               \r
1296                                   \r
1297   @retval EFI_SUCCESS           The operation on the PCI controller's attributes was completed.\r
1298   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.                              \r
1299   @retval EFI_UNSUPPORTED       one or more of the bits set in                               \r
1300                                 Attributes are not supported by this PCI controller or one of\r
1301                                 its parent bridges when Operation is Set, Enable or Disable.\r
1302                                        \r
1303 **/\r
1304 EFI_STATUS\r
1305 EFIAPI\r
1306 PciIoAttributes (\r
1307   IN EFI_PCI_IO_PROTOCOL                       * This,\r
1308   IN  EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION  Operation,\r
1309   IN  UINT64                                   Attributes,\r
1310   OUT UINT64                                   *Result OPTIONAL\r
1311   )\r
1312 {\r
1313   EFI_STATUS    Status;\r
1314 \r
1315   PCI_IO_DEVICE *PciIoDevice;\r
1316   PCI_IO_DEVICE *UpStreamBridge;\r
1317   PCI_IO_DEVICE *Temp;\r
1318 \r
1319   UINT64        Supports;\r
1320   UINT64        UpStreamAttributes;\r
1321   UINT16        BridgeControl;\r
1322   UINT16        Command;\r
1323 \r
1324   PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);\r
1325 \r
1326   switch (Operation) {\r
1327   case EfiPciIoAttributeOperationGet:\r
1328     if (Result == NULL) {\r
1329       return EFI_INVALID_PARAMETER;\r
1330     }\r
1331 \r
1332     *Result = PciIoDevice->Attributes;\r
1333     return EFI_SUCCESS;\r
1334 \r
1335   case EfiPciIoAttributeOperationSupported:\r
1336     if (Result == NULL) {\r
1337       return EFI_INVALID_PARAMETER;\r
1338     }\r
1339 \r
1340     *Result = PciIoDevice->Supports;\r
1341     return EFI_SUCCESS;\r
1342 \r
1343   case EfiPciIoAttributeOperationSet:\r
1344     Status = PciIoDevice->PciIo.Attributes (\r
1345                                   &(PciIoDevice->PciIo),\r
1346                                   EfiPciIoAttributeOperationEnable,\r
1347                                   Attributes,\r
1348                                   NULL\r
1349                                   );\r
1350     if (EFI_ERROR (Status)) {\r
1351       return EFI_UNSUPPORTED;\r
1352     }\r
1353 \r
1354     Status = PciIoDevice->PciIo.Attributes (\r
1355                                   &(PciIoDevice->PciIo),\r
1356                                   EfiPciIoAttributeOperationDisable,\r
1357                                   (~Attributes) & (PciIoDevice->Supports),\r
1358                                   NULL\r
1359                                   );\r
1360     if (EFI_ERROR (Status)) {\r
1361       return EFI_UNSUPPORTED;\r
1362     }\r
1363 \r
1364     return EFI_SUCCESS;\r
1365 \r
1366   case EfiPciIoAttributeOperationEnable:\r
1367   case EfiPciIoAttributeOperationDisable:\r
1368     break;\r
1369 \r
1370   default:\r
1371     return EFI_INVALID_PARAMETER;\r
1372   }\r
1373   //\r
1374   // Just a trick for ENABLE attribute\r
1375   // EFI_PCI_DEVICE_ENABLE is not defined in UEFI spec, which is the internal usage.\r
1376   // So, this logic doesn't confrom to UEFI spec, which should be removed.\r
1377   // But this trick logic is still kept for some binary drivers that depend on it.\r
1378   //\r
1379   if ((Attributes & EFI_PCI_DEVICE_ENABLE) == EFI_PCI_DEVICE_ENABLE) {\r
1380     Attributes &= (PciIoDevice->Supports);\r
1381 \r
1382     //\r
1383     // Raise the EFI_P_PC_ENABLE Status code\r
1384     //\r
1385     REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
1386       EFI_PROGRESS_CODE,\r
1387       EFI_IO_BUS_PCI | EFI_P_PC_ENABLE,\r
1388       PciIoDevice->DevicePath\r
1389       );\r
1390   }\r
1391 \r
1392   //\r
1393   // If no attributes can be supported, then return.\r
1394   // Otherwise, set the attributes that it can support.\r
1395   //\r
1396   Supports = (PciIoDevice->Supports) & Attributes;\r
1397   if (Supports != Attributes) {\r
1398     return EFI_UNSUPPORTED;\r
1399   }\r
1400    \r
1401   //\r
1402   // For Root Bridge, just call RootBridgeIo to set attributes;\r
1403   //\r
1404   if (!PciIoDevice->Parent) {\r
1405     Status = ModifyRootBridgeAttributes (PciIoDevice, Attributes, Operation);\r
1406     return Status;\r
1407   }\r
1408 \r
1409   Command       = 0;\r
1410   BridgeControl = 0;\r
1411 \r
1412   //\r
1413   // Check VGA and VGA16, they can not be set at the same time\r
1414   //\r
1415   if (((Attributes & EFI_PCI_IO_ATTRIBUTE_VGA_IO)         &&\r
1416        (Attributes & EFI_PCI_IO_ATTRIBUTE_VGA_IO_16))         ||\r
1417       ((Attributes & EFI_PCI_IO_ATTRIBUTE_VGA_IO)         &&\r
1418        (Attributes & EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16)) ||\r
1419       ((Attributes & EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO) &&\r
1420        (Attributes & EFI_PCI_IO_ATTRIBUTE_VGA_IO_16))         ||\r
1421       ((Attributes & EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO) &&\r
1422        (Attributes & EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16)) ) {\r
1423     return EFI_UNSUPPORTED;\r
1424   }\r
1425 \r
1426   //\r
1427   // For PPB & P2C, set relevant attribute bits\r
1428   //\r
1429   if (IS_PCI_BRIDGE (&PciIoDevice->Pci) || IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {\r
1430 \r
1431     if (Attributes & (EFI_PCI_IO_ATTRIBUTE_VGA_IO | EFI_PCI_IO_ATTRIBUTE_VGA_IO_16)) {\r
1432       BridgeControl |= EFI_PCI_BRIDGE_CONTROL_VGA;\r
1433     }\r
1434 \r
1435     if (Attributes & EFI_PCI_IO_ATTRIBUTE_ISA_IO) {\r
1436       BridgeControl |= EFI_PCI_BRIDGE_CONTROL_ISA;\r
1437     }\r
1438 \r
1439     if (Attributes & (EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO | EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16)) {\r
1440       Command |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO;\r
1441     }\r
1442 \r
1443     if (Attributes & (EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16 | EFI_PCI_IO_ATTRIBUTE_VGA_IO_16)) {\r
1444       BridgeControl |= EFI_PCI_BRIDGE_CONTROL_VGA_16;\r
1445     }\r
1446 \r
1447   } else {\r
1448     //\r
1449     // Do with the attributes on VGA\r
1450     // Only for VGA's legacy resource, we just can enable once.\r
1451     //\r
1452     if (Attributes &\r
1453         (EFI_PCI_IO_ATTRIBUTE_VGA_IO    |\r
1454          EFI_PCI_IO_ATTRIBUTE_VGA_IO_16 |\r
1455          EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY)) {\r
1456       //\r
1457       // Check if a VGA has been enabled before enabling a new one\r
1458       //\r
1459       if (Operation == EfiPciIoAttributeOperationEnable) {\r
1460         //\r
1461         // Check if there have been an active VGA device on the same segment\r
1462         //\r
1463         Temp = ActiveVGADeviceOnTheSameSegment (PciIoDevice);\r
1464         if (Temp && Temp != PciIoDevice) {\r
1465           //\r
1466           // An active VGA has been detected, so can not enable another\r
1467           //\r
1468           return EFI_UNSUPPORTED;\r
1469         }\r
1470       }\r
1471     }\r
1472     \r
1473     //\r
1474     // Do with the attributes on GFX\r
1475     //\r
1476     if (Attributes & (EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO | EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16)) {\r
1477 \r
1478       if (Operation == EfiPciIoAttributeOperationEnable) {\r
1479         //\r
1480         // Check if snoop can be enabled in current configuration\r
1481         //\r
1482         Status = SupportPaletteSnoopAttributes (PciIoDevice, Operation);\r
1483 \r
1484         if (EFI_ERROR (Status)) {\r
1485         \r
1486           //\r
1487           // Enable operation is forbidden, so mask the bit in attributes\r
1488           // so as to keep consistent with the actual Status\r
1489           //\r
1490           // Attributes &= (~EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO);\r
1491           //\r
1492           //\r
1493           //\r
1494           return EFI_UNSUPPORTED;\r
1495 \r
1496         }\r
1497       }\r
1498 \r
1499       //\r
1500       // It can be supported, so get ready to set the bit\r
1501       //\r
1502       Command |= EFI_PCI_COMMAND_VGA_PALETTE_SNOOP;\r
1503     }\r
1504   }\r
1505 \r
1506   if (Attributes & EFI_PCI_IO_ATTRIBUTE_IO) {\r
1507     Command |= EFI_PCI_COMMAND_IO_SPACE;\r
1508   }\r
1509 \r
1510   if (Attributes & EFI_PCI_IO_ATTRIBUTE_MEMORY) {\r
1511     Command |= EFI_PCI_COMMAND_MEMORY_SPACE;\r
1512   }\r
1513 \r
1514   if (Attributes & EFI_PCI_IO_ATTRIBUTE_BUS_MASTER) {\r
1515     Command |= EFI_PCI_COMMAND_BUS_MASTER;\r
1516   }\r
1517   //\r
1518   // The upstream bridge should be also set to revelant attribute\r
1519   // expect for IO, Mem and BusMaster\r
1520   //\r
1521   UpStreamAttributes = Attributes & \r
1522                        (~(EFI_PCI_IO_ATTRIBUTE_IO     |\r
1523                           EFI_PCI_IO_ATTRIBUTE_MEMORY |\r
1524                           EFI_PCI_IO_ATTRIBUTE_BUS_MASTER\r
1525                           )\r
1526                         );\r
1527   UpStreamBridge = PciIoDevice->Parent;\r
1528 \r
1529   if (Operation == EfiPciIoAttributeOperationEnable) {\r
1530     //\r
1531     // Enable relevant attributes to command register and bridge control register\r
1532     //\r
1533     Status = PciEnableCommandRegister (PciIoDevice, Command);\r
1534     if (BridgeControl) {\r
1535       Status = PciEnableBridgeControlRegister (PciIoDevice, BridgeControl);\r
1536     }\r
1537 \r
1538     PciIoDevice->Attributes |= Attributes;\r
1539 \r
1540     //\r
1541     // Enable attributes of the upstream bridge\r
1542     //\r
1543     Status = UpStreamBridge->PciIo.Attributes (\r
1544                                     &(UpStreamBridge->PciIo),\r
1545                                     EfiPciIoAttributeOperationEnable,\r
1546                                     UpStreamAttributes,\r
1547                                     NULL\r
1548                                     );\r
1549   } else {\r
1550     \r
1551     //\r
1552     // Disable relevant attributes to command register and bridge control register\r
1553     //\r
1554     Status = PciDisableCommandRegister (PciIoDevice, Command);\r
1555     if (BridgeControl) {\r
1556       Status = PciDisableBridgeControlRegister (PciIoDevice, BridgeControl);\r
1557     }\r
1558 \r
1559     PciIoDevice->Attributes &= (~Attributes);\r
1560     Status = EFI_SUCCESS;\r
1561 \r
1562   }\r
1563 \r
1564   if (EFI_ERROR (Status)) {\r
1565     ReportErrorStatusCode (PciIoDevice, EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR);\r
1566   }\r
1567 \r
1568   return Status;\r
1569 }\r
1570 \r
1571 /**                                                                 \r
1572   Gets the attributes that this PCI controller supports setting on a BAR using\r
1573   SetBarAttributes(), and retrieves the list of resource descriptors for a BAR.\r
1574             \r
1575   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.  \r
1576   @param  BarIndex              The BAR index of the standard PCI Configuration header to use as the\r
1577                                 base address for resource range. The legal range for this field is 0..5.\r
1578   @param  Supports              A pointer to the mask of attributes that this PCI controller supports\r
1579                                 setting for this BAR with SetBarAttributes().                        \r
1580   @param  Resources             A pointer to the ACPI 2.0 resource descriptors that describe the current\r
1581                                 configuration of this BAR of the PCI controller.                        \r
1582                                   \r
1583   @retval EFI_SUCCESS           If Supports is not NULL, then the attributes that the PCI       \r
1584                                 controller supports are returned in Supports. If Resources      \r
1585                                 is not NULL, then the ACPI 2.0 resource descriptors that the PCI\r
1586                                 controller is currently using are returned in Resources.          \r
1587   @retval EFI_INVALID_PARAMETER Both Supports and Attributes are NULL.\r
1588   @retval EFI_UNSUPPORTED       BarIndex not valid for this PCI controller.\r
1589   @retval EFI_OUT_OF_RESOURCES  There are not enough resources available to allocate\r
1590                                 Resources.                                                 \r
1591                                 \r
1592 **/\r
1593 EFI_STATUS\r
1594 EFIAPI\r
1595 PciIoGetBarAttributes (\r
1596   IN EFI_PCI_IO_PROTOCOL             * This,\r
1597   IN  UINT8                          BarIndex,\r
1598   OUT UINT64                         *Supports, OPTIONAL\r
1599   OUT VOID                           **Resources OPTIONAL\r
1600   )\r
1601 {\r
1602 \r
1603   UINT8                             *Configuration;\r
1604   UINT8                             NumConfig;\r
1605   PCI_IO_DEVICE                     *PciIoDevice;\r
1606   EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Ptr;\r
1607   EFI_ACPI_END_TAG_DESCRIPTOR       *PtrEnd;\r
1608 \r
1609   NumConfig   = 0;\r
1610 \r
1611   PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);\r
1612 \r
1613   if (Supports == NULL && Resources == NULL) {\r
1614     return EFI_INVALID_PARAMETER;\r
1615   }\r
1616 \r
1617   if (BarIndex >= PCI_MAX_BAR) {\r
1618     return EFI_UNSUPPORTED;\r
1619   }\r
1620 \r
1621   //\r
1622   // This driver does not support modifications to the WRITE_COMBINE or\r
1623   // CACHED attributes for BAR ranges.\r
1624   //\r
1625   if (Supports != NULL) {\r
1626     *Supports = PciIoDevice->Supports & EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED & EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE;\r
1627   }\r
1628 \r
1629   if (Resources != NULL) {\r
1630 \r
1631     if (PciIoDevice->PciBar[BarIndex].BarType != PciBarTypeUnknown) {\r
1632       NumConfig = 1;\r
1633     }\r
1634 \r
1635     Configuration = AllocatePool (sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) * NumConfig + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR));\r
1636     if (Configuration == NULL) {\r
1637       return EFI_OUT_OF_RESOURCES;\r
1638     }\r
1639 \r
1640     ZeroMem (\r
1641       Configuration,\r
1642       sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) * NumConfig + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR)\r
1643       );\r
1644 \r
1645     Ptr = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Configuration;\r
1646 \r
1647     if (NumConfig == 1) {\r
1648       Ptr->Desc         = ACPI_ADDRESS_SPACE_DESCRIPTOR;\r
1649       Ptr->Len          = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3;\r
1650 \r
1651       Ptr->AddrRangeMin = PciIoDevice->PciBar[BarIndex].BaseAddress;\r
1652       Ptr->AddrLen      = PciIoDevice->PciBar[BarIndex].Length;\r
1653       Ptr->AddrRangeMax = PciIoDevice->PciBar[BarIndex].Alignment;\r
1654 \r
1655       switch (PciIoDevice->PciBar[BarIndex].BarType) {\r
1656       case PciBarTypeIo16:\r
1657       case PciBarTypeIo32:\r
1658         //\r
1659         // Io\r
1660         //\r
1661         Ptr->ResType = ACPI_ADDRESS_SPACE_TYPE_IO;\r
1662         break;\r
1663 \r
1664       case PciBarTypeMem32:\r
1665         //\r
1666         // Mem\r
1667         //\r
1668         Ptr->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;\r
1669         //\r
1670         // 32 bit\r
1671         //\r
1672         Ptr->AddrSpaceGranularity = 32;\r
1673         break;\r
1674 \r
1675       case PciBarTypePMem32:\r
1676         //\r
1677         // Mem\r
1678         //\r
1679         Ptr->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;\r
1680         //\r
1681         // prefechable\r
1682         //\r
1683         Ptr->SpecificFlag = 0x6;\r
1684         //\r
1685         // 32 bit\r
1686         //\r
1687         Ptr->AddrSpaceGranularity = 32;\r
1688         break;\r
1689 \r
1690       case PciBarTypeMem64:\r
1691         //\r
1692         // Mem\r
1693         //\r
1694         Ptr->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;\r
1695         //\r
1696         // 64 bit\r
1697         //\r
1698         Ptr->AddrSpaceGranularity = 64;\r
1699         break;\r
1700 \r
1701       case PciBarTypePMem64:\r
1702         //\r
1703         // Mem\r
1704         //\r
1705         Ptr->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;\r
1706         //\r
1707         // prefechable\r
1708         //\r
1709         Ptr->SpecificFlag = 0x6;\r
1710         //\r
1711         // 64 bit\r
1712         //\r
1713         Ptr->AddrSpaceGranularity = 64;\r
1714         break;\r
1715 \r
1716       default:\r
1717         break;\r
1718       }\r
1719 \r
1720       Ptr = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) ((UINT8 *) Ptr + sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR));\r
1721     }\r
1722     \r
1723     //\r
1724     // put the checksum\r
1725     //\r
1726     PtrEnd            = (EFI_ACPI_END_TAG_DESCRIPTOR *) ((UINT8 *) Ptr);\r
1727     PtrEnd->Desc      = ACPI_END_TAG_DESCRIPTOR;\r
1728     PtrEnd->Checksum  = 0;\r
1729 \r
1730     *Resources        = Configuration;\r
1731   }\r
1732 \r
1733   return EFI_SUCCESS;\r
1734 }\r
1735 \r
1736 /**                                                                 \r
1737   Sets the attributes for a range of a BAR on a PCI controller.\r
1738             \r
1739   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.  \r
1740   @param  Attributes            The mask of attributes to set for the resource range specified by\r
1741                                 BarIndex, Offset, and Length.                                    \r
1742   @param  BarIndex              The BAR index of the standard PCI Configuration header to use as the\r
1743                                 base address for resource range. The legal range for this field is 0..5.\r
1744   @param  Offset                A pointer to the BAR relative base address of the resource range to be\r
1745                                 modified by the attributes specified by Attributes.                   \r
1746   @param  Length                A pointer to the length of the resource range to be modified by the\r
1747                                 attributes specified by Attributes.                                \r
1748                                   \r
1749   @retval EFI_SUCCESS           The set of attributes specified by Attributes for the resource      \r
1750                                 range specified by BarIndex, Offset, and Length were                \r
1751                                 set on the PCI controller, and the actual resource range is returned\r
1752                                 in Offset and Length.                                               \r
1753   @retval EFI_INVALID_PARAMETER Offset or Length is NULL.\r
1754   @retval EFI_UNSUPPORTED       BarIndex not valid for this PCI controller.\r
1755   @retval EFI_OUT_OF_RESOURCES  There are not enough resources to set the attributes on the\r
1756                                 resource range specified by BarIndex, Offset, and          \r
1757                                 Length.                                                    \r
1758                                 \r
1759 **/\r
1760 EFI_STATUS\r
1761 EFIAPI\r
1762 PciIoSetBarAttributes (\r
1763   IN EFI_PCI_IO_PROTOCOL              *This,\r
1764   IN     UINT64                       Attributes,\r
1765   IN     UINT8                        BarIndex,\r
1766   IN OUT UINT64                       *Offset,\r
1767   IN OUT UINT64                       *Length\r
1768   )\r
1769 {\r
1770   EFI_STATUS    Status;\r
1771   PCI_IO_DEVICE *PciIoDevice;\r
1772   UINT64        NonRelativeOffset;\r
1773   UINT64        Supports;\r
1774 \r
1775   PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);\r
1776 \r
1777   //\r
1778   // Make sure Offset and Length are not NULL\r
1779   //\r
1780   if (Offset == NULL || Length == NULL) {\r
1781     return EFI_INVALID_PARAMETER;\r
1782   }\r
1783 \r
1784   if (PciIoDevice->PciBar[BarIndex].BarType == PciBarTypeUnknown) {\r
1785     return EFI_UNSUPPORTED;\r
1786   }\r
1787   //\r
1788   // This driver does not support setting the WRITE_COMBINE or the CACHED attributes.\r
1789   // If Attributes is not 0, then return EFI_UNSUPPORTED.\r
1790   //\r
1791   Supports = PciIoDevice->Supports & EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED & EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE;\r
1792 \r
1793   if (Attributes != (Attributes & Supports)) {\r
1794     return EFI_UNSUPPORTED;\r
1795   }\r
1796   //\r
1797   // Attributes must be supported.  Make sure the BAR range describd by BarIndex, Offset, and\r
1798   // Length are valid for this PCI device.\r
1799   //\r
1800   NonRelativeOffset = *Offset;\r
1801   Status = PciIoVerifyBarAccess (\r
1802             PciIoDevice,\r
1803             BarIndex,\r
1804             PciBarTypeMem,\r
1805             EfiPciIoWidthUint8,\r
1806             (UINT32) *Length,\r
1807             &NonRelativeOffset\r
1808             );\r
1809   if (EFI_ERROR (Status)) {\r
1810     return EFI_UNSUPPORTED;\r
1811   }\r
1812 \r
1813   return EFI_SUCCESS;\r
1814 }\r
1815 \r
1816 /**\r
1817   Program parent bridge's attribute recurrently.\r
1818   \r
1819   @param PciIoDevice  Child Pci device instance\r
1820   @param Operation    The operation to perform on the attributes for this PCI controller.\r
1821   @param Attributes   The mask of attributes that are used for Set, Enable, and Disable\r
1822                       operations.\r
1823                       \r
1824   @retval EFI_SUCCESS           The operation on the PCI controller's attributes was completed.\r
1825   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.                              \r
1826   @retval EFI_UNSUPPORTED       one or more of the bits set in                               \r
1827                                 Attributes are not supported by this PCI controller or one of\r
1828                                 its parent bridges when Operation is Set, Enable or Disable.\r
1829              \r
1830 **/\r
1831 EFI_STATUS\r
1832 UpStreamBridgesAttributes (\r
1833   IN  PCI_IO_DEVICE                            *PciIoDevice,\r
1834   IN  EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION  Operation,\r
1835   IN  UINT64                                   Attributes\r
1836   )\r
1837 {\r
1838   PCI_IO_DEVICE       *Parent;\r
1839   EFI_PCI_IO_PROTOCOL *PciIo;\r
1840 \r
1841   Parent = PciIoDevice->Parent;\r
1842 \r
1843   while (Parent && IS_PCI_BRIDGE (&Parent->Pci)) {\r
1844 \r
1845     //\r
1846     // Get the PciIo Protocol\r
1847     //\r
1848     PciIo = &Parent->PciIo;\r
1849 \r
1850     PciIo->Attributes (PciIo, Operation, Attributes, NULL);\r
1851 \r
1852     Parent = Parent->Parent;\r
1853   }\r
1854 \r
1855   return EFI_SUCCESS;\r
1856 }\r
1857 \r
1858 /**\r
1859   Test whether two Pci device has same parent bridge.\r
1860   \r
1861   @param PciDevice1  the frist pci device for testing\r
1862   @param PciDevice2  the second pci device for testing\r
1863   \r
1864   @return whether two Pci device has same parent bridge.\r
1865 **/\r
1866 BOOLEAN\r
1867 PciDevicesOnTheSamePath (\r
1868   IN PCI_IO_DEVICE        *PciDevice1,\r
1869   IN PCI_IO_DEVICE        *PciDevice2\r
1870   )\r
1871 {\r
1872   BOOLEAN   Existed1;\r
1873   BOOLEAN   Existed2;\r
1874 \r
1875   if (PciDevice1->Parent == PciDevice2->Parent) {\r
1876     return TRUE;\r
1877   }\r
1878 \r
1879   Existed1 = PciDeviceExisted (PciDevice1->Parent, PciDevice2);\r
1880   Existed2 = PciDeviceExisted (PciDevice2->Parent, PciDevice1);\r
1881 \r
1882   return (BOOLEAN) (Existed1 || Existed2);\r
1883 }\r
1884 \r