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