1/** @file
2  EFI PCI IO protocol functions implementation for PCI Bus module.
3
4Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
5This program and the accompanying materials
6are licensed and made available under the terms and conditions of the BSD License
7which accompanies this distribution.  The full text of the license may be found at
8http://opensource.org/licenses/bsd-license.php
9
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11WITHOUT 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//
20EFI_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**/
55VOID
56InitializePciIoInstance (
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**/
78EFI_STATUS
79PciIoVerifyBarAccess (
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**/
139EFI_STATUS
140PciIoVerifyConfigAccess (
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**/
200EFI_STATUS
201EFIAPI
202PciIoPollMem (
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**/
307EFI_STATUS
308EFIAPI
309PciIoPollIo (
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**/
408EFI_STATUS
409EFIAPI
410PciIoMemRead (
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**/
487EFI_STATUS
488EFIAPI
489PciIoMemWrite (
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**/
565EFI_STATUS
566EFIAPI
567PciIoIoRead (
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**/
643EFI_STATUS
644EFIAPI
645PciIoIoWrite (
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**/
719EFI_STATUS
720EFIAPI
721PciIoConfigRead (
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**/
788EFI_STATUS
789EFIAPI
790PciIoConfigWrite (
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**/
867EFI_STATUS
868EFIAPI
869PciIoCopyMem (
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**/
957EFI_STATUS
958EFIAPI
959PciIoMap (
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**/
1015EFI_STATUS
1016EFIAPI
1017PciIoUnmap (
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**/
1063EFI_STATUS
1064EFIAPI
1065PciIoAllocateBuffer (
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**/
1120EFI_STATUS
1121EFIAPI
1122PciIoFreeBuffer (
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**/
1161EFI_STATUS
1162EFIAPI
1163PciIoFlush (
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**/
1199EFI_STATUS
1200EFIAPI
1201PciIoGetLocation (
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**/
1237BOOLEAN
1238CheckBarType (
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**/
1283EFI_STATUS
1284ModifyRootBridgeAttributes (
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**/
1360EFI_STATUS
1361SupportPaletteSnoopAttributes (
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**/
1480EFI_STATUS
1481EFIAPI
1482PciIoAttributes (
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  Gets the attributes that this PCI controller supports setting on a BAR using
1748  SetBarAttributes(), and retrieves the list of resource descriptors for a BAR.
1749
1750  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
1751  @param  BarIndex              The BAR index of the standard PCI Configuration header to use as the
1752                                base address for resource range. The legal range for this field is 0..5.
1753  @param  Supports              A pointer to the mask of attributes that this PCI controller supports
1754                                setting for this BAR with SetBarAttributes().
1755  @param  Resources             A pointer to the ACPI 2.0 resource descriptors that describe the current
1756                                configuration of this BAR of the PCI controller.
1757
1758  @retval EFI_SUCCESS           If Supports is not NULL, then the attributes that the PCI
1759                                controller supports are returned in Supports. If Resources
1760                                is not NULL, then the ACPI 2.0 resource descriptors that the PCI
1761                                controller is currently using are returned in Resources.
1762  @retval EFI_INVALID_PARAMETER Both Supports and Attributes are NULL.
1763  @retval EFI_UNSUPPORTED       BarIndex not valid for this PCI controller.
1764  @retval EFI_OUT_OF_RESOURCES  There are not enough resources available to allocate
1765                                Resources.
1766
1767**/
1768EFI_STATUS
1769EFIAPI
1770PciIoGetBarAttributes (
1771  IN EFI_PCI_IO_PROTOCOL             * This,
1772  IN  UINT8                          BarIndex,
1773  OUT UINT64                         *Supports, OPTIONAL
1774  OUT VOID                           **Resources OPTIONAL
1775  )
1776{
1777  UINT8                             *Configuration;
1778  PCI_IO_DEVICE                     *PciIoDevice;
1779  EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *AddressSpace;
1780  EFI_ACPI_END_TAG_DESCRIPTOR       *End;
1781
1782  PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
1783
1784  if (Supports == NULL && Resources == NULL) {
1785    return EFI_INVALID_PARAMETER;
1786  }
1787
1788  if ((BarIndex >= PCI_MAX_BAR) || (PciIoDevice->PciBar[BarIndex].BarType == PciBarTypeUnknown)) {
1789    return EFI_UNSUPPORTED;
1790  }
1791
1792  //
1793  // This driver does not support modifications to the WRITE_COMBINE or
1794  // CACHED attributes for BAR ranges.
1795  //
1796  if (Supports != NULL) {
1797    *Supports = PciIoDevice->Supports & EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED & EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE;
1798  }
1799
1800  if (Resources != NULL) {
1801    Configuration = AllocateZeroPool (sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR));
1802    if (Configuration == NULL) {
1803      return EFI_OUT_OF_RESOURCES;
1804    }
1805
1806    AddressSpace = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Configuration;
1807
1808    AddressSpace->Desc         = ACPI_ADDRESS_SPACE_DESCRIPTOR;
1809    AddressSpace->Len          = (UINT16) (sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3);
1810
1811    AddressSpace->AddrRangeMin = PciIoDevice->PciBar[BarIndex].BaseAddress;
1812    AddressSpace->AddrLen      = PciIoDevice->PciBar[BarIndex].Length;
1813    AddressSpace->AddrRangeMax = PciIoDevice->PciBar[BarIndex].Alignment;
1814
1815    switch (PciIoDevice->PciBar[BarIndex].BarType) {
1816    case PciBarTypeIo16:
1817    case PciBarTypeIo32:
1818      //
1819      // Io
1820      //
1821      AddressSpace->ResType = ACPI_ADDRESS_SPACE_TYPE_IO;
1822      break;
1823
1824    case PciBarTypeMem32:
1825      //
1826      // Mem
1827      //
1828      AddressSpace->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;
1829      //
1830      // 32 bit
1831      //
1832      AddressSpace->AddrSpaceGranularity = 32;
1833      break;
1834
1835    case PciBarTypePMem32:
1836      //
1837      // Mem
1838      //
1839      AddressSpace->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;
1840      //
1841      // prefechable
1842      //
1843      AddressSpace->SpecificFlag = 0x6;
1844      //
1845      // 32 bit
1846      //
1847      AddressSpace->AddrSpaceGranularity = 32;
1848      break;
1849
1850    case PciBarTypeMem64:
1851      //
1852      // Mem
1853      //
1854      AddressSpace->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;
1855      //
1856      // 64 bit
1857      //
1858      AddressSpace->AddrSpaceGranularity = 64;
1859      break;
1860
1861    case PciBarTypePMem64:
1862      //
1863      // Mem
1864      //
1865      AddressSpace->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;
1866      //
1867      // prefechable
1868      //
1869      AddressSpace->SpecificFlag = 0x6;
1870      //
1871      // 64 bit
1872      //
1873      AddressSpace->AddrSpaceGranularity = 64;
1874      break;
1875
1876    default:
1877      break;
1878    }
1879
1880    //
1881    // put the checksum
1882    //
1883    End           = (EFI_ACPI_END_TAG_DESCRIPTOR *) (AddressSpace + 1);
1884    End->Desc     = ACPI_END_TAG_DESCRIPTOR;
1885    End->Checksum = 0;
1886
1887    *Resources    = Configuration;
1888  }
1889
1890  return EFI_SUCCESS;
1891}
1892
1893/**
1894  Sets the attributes for a range of a BAR on a PCI controller.
1895
1896  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
1897  @param  Attributes            The mask of attributes to set for the resource range specified by
1898                                BarIndex, Offset, and Length.
1899  @param  BarIndex              The BAR index of the standard PCI Configuration header to use as the
1900                                base address for resource range. The legal range for this field is 0..5.
1901  @param  Offset                A pointer to the BAR relative base address of the resource range to be
1902                                modified by the attributes specified by Attributes.
1903  @param  Length                A pointer to the length of the resource range to be modified by the
1904                                attributes specified by Attributes.
1905
1906  @retval EFI_SUCCESS           The set of attributes specified by Attributes for the resource
1907                                range specified by BarIndex, Offset, and Length were
1908                                set on the PCI controller, and the actual resource range is returned
1909                                in Offset and Length.
1910  @retval EFI_INVALID_PARAMETER Offset or Length is NULL.
1911  @retval EFI_UNSUPPORTED       BarIndex not valid for this PCI controller.
1912  @retval EFI_OUT_OF_RESOURCES  There are not enough resources to set the attributes on the
1913                                resource range specified by BarIndex, Offset, and
1914                                Length.
1915
1916**/
1917EFI_STATUS
1918EFIAPI
1919PciIoSetBarAttributes (
1920  IN EFI_PCI_IO_PROTOCOL              *This,
1921  IN     UINT64                       Attributes,
1922  IN     UINT8                        BarIndex,
1923  IN OUT UINT64                       *Offset,
1924  IN OUT UINT64                       *Length
1925  )
1926{
1927  EFI_STATUS    Status;
1928  PCI_IO_DEVICE *PciIoDevice;
1929  UINT64        NonRelativeOffset;
1930  UINT64        Supports;
1931
1932  PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
1933
1934  //
1935  // Make sure Offset and Length are not NULL
1936  //
1937  if (Offset == NULL || Length == NULL) {
1938    return EFI_INVALID_PARAMETER;
1939  }
1940
1941  if (PciIoDevice->PciBar[BarIndex].BarType == PciBarTypeUnknown) {
1942    return EFI_UNSUPPORTED;
1943  }
1944  //
1945  // This driver does not support setting the WRITE_COMBINE or the CACHED attributes.
1946  // If Attributes is not 0, then return EFI_UNSUPPORTED.
1947  //
1948  Supports = PciIoDevice->Supports & EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED & EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE;
1949
1950  if (Attributes != (Attributes & Supports)) {
1951    return EFI_UNSUPPORTED;
1952  }
1953  //
1954  // Attributes must be supported.  Make sure the BAR range describd by BarIndex, Offset, and
1955  // Length are valid for this PCI device.
1956  //
1957  NonRelativeOffset = *Offset;
1958  Status = PciIoVerifyBarAccess (
1959            PciIoDevice,
1960            BarIndex,
1961            PciBarTypeMem,
1962            EfiPciIoWidthUint8,
1963            (UINT32) *Length,
1964            &NonRelativeOffset
1965            );
1966  if (EFI_ERROR (Status)) {
1967    return EFI_UNSUPPORTED;
1968  }
1969
1970  return EFI_SUCCESS;
1971}
1972
1973/**
1974  Program parent bridge's attribute recurrently.
1975
1976  @param PciIoDevice  Child Pci device instance
1977  @param Operation    The operation to perform on the attributes for this PCI controller.
1978  @param Attributes   The mask of attributes that are used for Set, Enable, and Disable
1979                      operations.
1980
1981  @retval EFI_SUCCESS           The operation on the PCI controller's attributes was completed.
1982  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
1983  @retval EFI_UNSUPPORTED       one or more of the bits set in
1984                                Attributes are not supported by this PCI controller or one of
1985                                its parent bridges when Operation is Set, Enable or Disable.
1986
1987**/
1988EFI_STATUS
1989UpStreamBridgesAttributes (
1990  IN PCI_IO_DEVICE                            *PciIoDevice,
1991  IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION  Operation,
1992  IN UINT64                                   Attributes
1993  )
1994{
1995  PCI_IO_DEVICE       *Parent;
1996  EFI_PCI_IO_PROTOCOL *PciIo;
1997
1998  Parent = PciIoDevice->Parent;
1999
2000  while (Parent != NULL && IS_PCI_BRIDGE (&Parent->Pci)) {
2001
2002    //
2003    // Get the PciIo Protocol
2004    //
2005    PciIo = &Parent->PciIo;
2006
2007    PciIo->Attributes (PciIo, Operation, Attributes, NULL);
2008
2009    Parent = Parent->Parent;
2010  }
2011
2012  return EFI_SUCCESS;
2013}
2014
2015/**
2016  Test whether two Pci devices has same parent bridge.
2017
2018  @param PciDevice1  The first pci device for testing.
2019  @param PciDevice2  The second pci device for testing.
2020
2021  @retval TRUE       Two Pci device has the same parent bridge.
2022  @retval FALSE      Two Pci device has not the same parent bridge.
2023
2024**/
2025BOOLEAN
2026PciDevicesOnTheSamePath (
2027  IN PCI_IO_DEVICE        *PciDevice1,
2028  IN PCI_IO_DEVICE        *PciDevice2
2029  )
2030{
2031  BOOLEAN   Existed1;
2032  BOOLEAN   Existed2;
2033
2034  if (PciDevice1->Parent == PciDevice2->Parent) {
2035    return TRUE;
2036  }
2037
2038  Existed1 = PciDeviceExisted (PciDevice1->Parent, PciDevice2);
2039  Existed2 = PciDeviceExisted (PciDevice2->Parent, PciDevice1);
2040
2041  return (BOOLEAN) (Existed1 || Existed2);
2042}
2043
2044