MdeModulePkg/SdMmcPciHcDxe: Fix PIO transfer mode
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / NonDiscoverablePciDeviceDxe / NonDiscoverablePciDeviceIo.c
1 /** @file\r
2 \r
3   Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>\r
4   Copyright (c) 2016, Linaro, Ltd. All rights reserved.<BR>\r
5 \r
6   SPDX-License-Identifier: BSD-2-Clause-Patent\r
7 \r
8 **/\r
9 \r
10 #include "NonDiscoverablePciDeviceIo.h"\r
11 \r
12 #include <Library/DxeServicesTableLib.h>\r
13 \r
14 #include <IndustryStandard/Acpi.h>\r
15 \r
16 #include <Protocol/PciRootBridgeIo.h>\r
17 \r
18 typedef struct {\r
19   EFI_PHYSICAL_ADDRESS            AllocAddress;\r
20   VOID                            *HostAddress;\r
21   EFI_PCI_IO_PROTOCOL_OPERATION   Operation;\r
22   UINTN                           NumberOfBytes;\r
23 } NON_DISCOVERABLE_PCI_DEVICE_MAP_INFO;\r
24 \r
25 /**\r
26   Get the resource associated with BAR number 'BarIndex'.\r
27 \r
28   @param  Dev           Point to the NON_DISCOVERABLE_PCI_DEVICE instance.\r
29   @param  BarIndex      The BAR index of the standard PCI Configuration header to use as the\r
30                         base address for the memory operation to perform.\r
31   @param  Descriptor    Points to the address space descriptor\r
32 **/\r
33 STATIC\r
34 EFI_STATUS\r
35 GetBarResource (\r
36   IN  NON_DISCOVERABLE_PCI_DEVICE         *Dev,\r
37   IN  UINT8                               BarIndex,\r
38   OUT EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR   **Descriptor\r
39   )\r
40 {\r
41   EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR   *Desc;\r
42 \r
43   if (BarIndex < Dev->BarOffset) {\r
44     return EFI_NOT_FOUND;\r
45   }\r
46 \r
47   BarIndex -= (UINT8)Dev->BarOffset;\r
48 \r
49   if (BarIndex >= Dev->BarCount) {\r
50     return EFI_UNSUPPORTED;\r
51   }\r
52 \r
53   for (Desc = Dev->Device->Resources;\r
54        Desc->Desc != ACPI_END_TAG_DESCRIPTOR;\r
55        Desc = (VOID *)((UINT8 *)Desc + Desc->Len + 3)) {\r
56 \r
57     if (BarIndex == 0) {\r
58       *Descriptor = Desc;\r
59       return EFI_SUCCESS;\r
60     }\r
61 \r
62     BarIndex -= 1;\r
63   }\r
64   return EFI_NOT_FOUND;\r
65 }\r
66 \r
67 /**\r
68   Reads from the memory space of a PCI controller. Returns either when the polling exit criteria is\r
69   satisfied or after a defined duration.\r
70 \r
71   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
72   @param  Width                 Signifies the width of the memory or I/O operations.\r
73   @param  BarIndex              The BAR index of the standard PCI Configuration header to use as the\r
74                                 base address for the memory operation to perform.\r
75   @param  Offset                The offset within the selected BAR to start the memory operation.\r
76   @param  Mask                  Mask used for the polling criteria.\r
77   @param  Value                 The comparison value used for the polling exit criteria.\r
78   @param  Delay                 The number of 100 ns units to poll.\r
79   @param  Result                Pointer to the last value read from the memory location.\r
80 \r
81 **/\r
82 STATIC\r
83 EFI_STATUS\r
84 EFIAPI\r
85 PciIoPollMem (\r
86   IN  EFI_PCI_IO_PROTOCOL         *This,\r
87   IN  EFI_PCI_IO_PROTOCOL_WIDTH   Width,\r
88   IN  UINT8                       BarIndex,\r
89   IN  UINT64                      Offset,\r
90   IN  UINT64                      Mask,\r
91   IN  UINT64                      Value,\r
92   IN  UINT64                      Delay,\r
93   OUT UINT64                      *Result\r
94   )\r
95 {\r
96   ASSERT (FALSE);\r
97   return EFI_UNSUPPORTED;\r
98 }\r
99 \r
100 /**\r
101   Reads from the memory space of a PCI controller. Returns either when the polling exit criteria is\r
102   satisfied or after a defined duration.\r
103 \r
104   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
105   @param  Width                 Signifies the width of the memory or I/O operations.\r
106   @param  BarIndex              The BAR index of the standard PCI Configuration header to use as the\r
107                                 base address for the memory operation to perform.\r
108   @param  Offset                The offset within the selected BAR to start the memory operation.\r
109   @param  Mask                  Mask used for the polling criteria.\r
110   @param  Value                 The comparison value used for the polling exit criteria.\r
111   @param  Delay                 The number of 100 ns units to poll.\r
112   @param  Result                Pointer to the last value read from the memory location.\r
113 \r
114 **/\r
115 STATIC\r
116 EFI_STATUS\r
117 EFIAPI\r
118 PciIoPollIo (\r
119   IN  EFI_PCI_IO_PROTOCOL         *This,\r
120   IN  EFI_PCI_IO_PROTOCOL_WIDTH   Width,\r
121   IN  UINT8                       BarIndex,\r
122   IN  UINT64                      Offset,\r
123   IN  UINT64                      Mask,\r
124   IN  UINT64                      Value,\r
125   IN  UINT64                      Delay,\r
126   OUT UINT64                      *Result\r
127   )\r
128 {\r
129   ASSERT (FALSE);\r
130   return EFI_UNSUPPORTED;\r
131 }\r
132 \r
133 /**\r
134   Enable a PCI driver to access PCI controller registers in the PCI memory or I/O space.\r
135 \r
136   @param  Width         Signifies the width of the memory or I/O operations.\r
137   @param  Count         The number of memory or I/O operations to perform.\r
138   @param  DstStride     The stride of the destination buffer.\r
139   @param  Dst           For read operations, the destination buffer to store the results. For write\r
140                         operations, the destination buffer to write data to.\r
141   @param  SrcStride     The stride of the source buffer.\r
142   @param  Src           For read operations, the source buffer to read data from. For write\r
143                         operations, the source buffer to write data from.\r
144 \r
145   @retval EFI_SUCCESS            The data was read from or written to the PCI controller.\r
146   @retval EFI_INVALID_PARAMETER  One or more parameters are invalid.\r
147 \r
148 **/\r
149 STATIC\r
150 EFI_STATUS\r
151 EFIAPI\r
152 PciIoMemRW (\r
153   IN  EFI_PCI_IO_PROTOCOL_WIDTH   Width,\r
154   IN  UINTN                       Count,\r
155   IN  UINTN                       DstStride,\r
156   IN  VOID                        *Dst,\r
157   IN  UINTN                       SrcStride,\r
158   OUT CONST VOID                  *Src\r
159   )\r
160 {\r
161   volatile UINT8             *Dst8;\r
162   volatile UINT16            *Dst16;\r
163   volatile UINT32            *Dst32;\r
164   volatile CONST UINT8       *Src8;\r
165   volatile CONST UINT16      *Src16;\r
166   volatile CONST UINT32      *Src32;\r
167 \r
168   //\r
169   // Loop for each iteration and move the data\r
170   //\r
171   switch (Width & 0x3) {\r
172   case EfiPciWidthUint8:\r
173     Dst8 = (UINT8 *)Dst;\r
174     Src8 = (UINT8 *)Src;\r
175     for (;Count > 0; Count--, Dst8 += DstStride, Src8 += SrcStride) {\r
176       *Dst8 = *Src8;\r
177     }\r
178     break;\r
179   case EfiPciWidthUint16:\r
180     Dst16 = (UINT16 *)Dst;\r
181     Src16 = (UINT16 *)Src;\r
182     for (;Count > 0; Count--, Dst16 += DstStride, Src16 += SrcStride) {\r
183       *Dst16 = *Src16;\r
184     }\r
185     break;\r
186   case EfiPciWidthUint32:\r
187     Dst32 = (UINT32 *)Dst;\r
188     Src32 = (UINT32 *)Src;\r
189     for (;Count > 0; Count--, Dst32 += DstStride, Src32 += SrcStride) {\r
190       *Dst32 = *Src32;\r
191     }\r
192     break;\r
193   default:\r
194     return EFI_INVALID_PARAMETER;\r
195   }\r
196 \r
197   return EFI_SUCCESS;\r
198 }\r
199 \r
200 /**\r
201   Enable a PCI driver to access PCI controller registers in the PCI memory or I/O space.\r
202 \r
203   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
204   @param  Width                 Signifies the width of the memory or I/O operations.\r
205   @param  BarIndex              The BAR index of the standard PCI Configuration header to use as the\r
206                                 base address for the memory or I/O operation to perform.\r
207   @param  Offset                The offset within the selected BAR to start the memory or I/O operation.\r
208   @param  Count                 The number of memory or I/O operations to perform.\r
209   @param  Buffer                For read operations, the destination buffer to store the results. For write\r
210                                 operations, the source buffer to write data from.\r
211 \r
212   @retval EFI_SUCCESS           The data was read from or written to the PCI controller.\r
213   @retval EFI_UNSUPPORTED       BarIndex not valid for this PCI controller.\r
214   @retval EFI_UNSUPPORTED       The address range specified by Offset, Width, and Count is not\r
215                                 valid for the PCI BAR specified by BarIndex.\r
216   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.\r
217   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
218 \r
219 **/\r
220 STATIC\r
221 EFI_STATUS\r
222 EFIAPI\r
223 PciIoMemRead (\r
224   IN     EFI_PCI_IO_PROTOCOL          *This,\r
225   IN     EFI_PCI_IO_PROTOCOL_WIDTH    Width,\r
226   IN     UINT8                        BarIndex,\r
227   IN     UINT64                       Offset,\r
228   IN     UINTN                        Count,\r
229   IN OUT VOID                         *Buffer\r
230   )\r
231 {\r
232   NON_DISCOVERABLE_PCI_DEVICE         *Dev;\r
233   UINTN                               AlignMask;\r
234   VOID                                *Address;\r
235   EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR   *Desc;\r
236   EFI_STATUS                          Status;\r
237 \r
238   if (Buffer == NULL) {\r
239     return EFI_INVALID_PARAMETER;\r
240   }\r
241 \r
242   Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);\r
243 \r
244   //\r
245   // Only allow accesses to the BARs we emulate\r
246   //\r
247   Status = GetBarResource (Dev, BarIndex, &Desc);\r
248   if (EFI_ERROR (Status)) {\r
249     return Status;\r
250   }\r
251 \r
252   if (Offset + (Count << (Width & 0x3)) > Desc->AddrLen) {\r
253     return EFI_UNSUPPORTED;\r
254   }\r
255 \r
256   Address = (VOID *)(UINTN)(Desc->AddrRangeMin + Offset);\r
257   AlignMask = (1 << (Width & 0x03)) - 1;\r
258   if ((UINTN)Address & AlignMask) {\r
259     return EFI_INVALID_PARAMETER;\r
260   }\r
261 \r
262   switch (Width) {\r
263   case EfiPciIoWidthUint8:\r
264   case EfiPciIoWidthUint16:\r
265   case EfiPciIoWidthUint32:\r
266   case EfiPciIoWidthUint64:\r
267     return PciIoMemRW (Width, Count, 1, Buffer, 1, Address);\r
268 \r
269   case EfiPciIoWidthFifoUint8:\r
270   case EfiPciIoWidthFifoUint16:\r
271   case EfiPciIoWidthFifoUint32:\r
272   case EfiPciIoWidthFifoUint64:\r
273     return PciIoMemRW (Width, Count, 1, Buffer, 0, Address);\r
274 \r
275   case EfiPciIoWidthFillUint8:\r
276   case EfiPciIoWidthFillUint16:\r
277   case EfiPciIoWidthFillUint32:\r
278   case EfiPciIoWidthFillUint64:\r
279     return PciIoMemRW (Width, Count, 0, Buffer, 1, Address);\r
280 \r
281   default:\r
282     break;\r
283   }\r
284   return EFI_INVALID_PARAMETER;\r
285 }\r
286 \r
287 /**\r
288   Enable a PCI driver to access PCI controller registers in the PCI memory or I/O space.\r
289 \r
290   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
291   @param  Width                 Signifies the width of the memory or I/O operations.\r
292   @param  BarIndex              The BAR index of the standard PCI Configuration header to use as the\r
293                                 base address for the memory or I/O operation to perform.\r
294   @param  Offset                The offset within the selected BAR to start the memory or I/O operation.\r
295   @param  Count                 The number of memory or I/O operations to perform.\r
296   @param  Buffer                For read operations, the destination buffer to store the results. For write\r
297                                 operations, the source buffer to write data from.\r
298 \r
299   @retval EFI_SUCCESS           The data was read from or written to the PCI controller.\r
300   @retval EFI_UNSUPPORTED       BarIndex not valid for this PCI controller.\r
301   @retval EFI_UNSUPPORTED       The address range specified by Offset, Width, and Count is not\r
302                                 valid for the PCI BAR specified by BarIndex.\r
303   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.\r
304   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
305 \r
306 **/\r
307 STATIC\r
308 EFI_STATUS\r
309 EFIAPI\r
310 PciIoMemWrite (\r
311   IN     EFI_PCI_IO_PROTOCOL          *This,\r
312   IN     EFI_PCI_IO_PROTOCOL_WIDTH    Width,\r
313   IN     UINT8                        BarIndex,\r
314   IN     UINT64                       Offset,\r
315   IN     UINTN                        Count,\r
316   IN OUT VOID                         *Buffer\r
317   )\r
318 {\r
319   NON_DISCOVERABLE_PCI_DEVICE         *Dev;\r
320   UINTN                               AlignMask;\r
321   VOID                                *Address;\r
322   EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR   *Desc;\r
323   EFI_STATUS                          Status;\r
324 \r
325   if (Buffer == NULL) {\r
326     return EFI_INVALID_PARAMETER;\r
327   }\r
328 \r
329   Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);\r
330 \r
331   //\r
332   // Only allow accesses to the BARs we emulate\r
333   //\r
334   Status = GetBarResource (Dev, BarIndex, &Desc);\r
335   if (EFI_ERROR (Status)) {\r
336     return Status;\r
337   }\r
338 \r
339   if (Offset + (Count << (Width & 0x3)) > Desc->AddrLen) {\r
340     return EFI_UNSUPPORTED;\r
341   }\r
342 \r
343   Address = (VOID *)(UINTN)(Desc->AddrRangeMin + Offset);\r
344   AlignMask = (1 << (Width & 0x03)) - 1;\r
345   if ((UINTN)Address & AlignMask) {\r
346     return EFI_INVALID_PARAMETER;\r
347   }\r
348 \r
349   switch (Width) {\r
350   case EfiPciIoWidthUint8:\r
351   case EfiPciIoWidthUint16:\r
352   case EfiPciIoWidthUint32:\r
353   case EfiPciIoWidthUint64:\r
354     return PciIoMemRW (Width, Count, 1, Address, 1, Buffer);\r
355 \r
356   case EfiPciIoWidthFifoUint8:\r
357   case EfiPciIoWidthFifoUint16:\r
358   case EfiPciIoWidthFifoUint32:\r
359   case EfiPciIoWidthFifoUint64:\r
360     return PciIoMemRW (Width, Count, 0, Address, 1, Buffer);\r
361 \r
362   case EfiPciIoWidthFillUint8:\r
363   case EfiPciIoWidthFillUint16:\r
364   case EfiPciIoWidthFillUint32:\r
365   case EfiPciIoWidthFillUint64:\r
366     return PciIoMemRW (Width, Count, 1, Address, 0, Buffer);\r
367 \r
368   default:\r
369     break;\r
370   }\r
371   return EFI_INVALID_PARAMETER;\r
372 }\r
373 \r
374 /**\r
375   Enable a PCI driver to access PCI controller registers in the PCI memory or I/O space.\r
376 \r
377   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
378   @param  Width                 Signifies the width of the memory or I/O operations.\r
379   @param  BarIndex              The BAR index of the standard PCI Configuration header to use as the\r
380                                 base address for the memory or I/O operation to perform.\r
381   @param  Offset                The offset within the selected BAR to start the memory or I/O operation.\r
382   @param  Count                 The number of memory or I/O operations to perform.\r
383   @param  Buffer                For read operations, the destination buffer to store the results. For write\r
384                                 operations, the source buffer to write data from.\r
385 \r
386 **/\r
387 STATIC\r
388 EFI_STATUS\r
389 EFIAPI\r
390 PciIoIoRead (\r
391   IN EFI_PCI_IO_PROTOCOL              *This,\r
392   IN     EFI_PCI_IO_PROTOCOL_WIDTH    Width,\r
393   IN     UINT8                        BarIndex,\r
394   IN     UINT64                       Offset,\r
395   IN     UINTN                        Count,\r
396   IN OUT VOID                         *Buffer\r
397   )\r
398 {\r
399   ASSERT (FALSE);\r
400   return EFI_UNSUPPORTED;\r
401 }\r
402 \r
403 /**\r
404   Enable a PCI driver to access PCI controller registers in the PCI memory or I/O space.\r
405 \r
406   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
407   @param  Width                 Signifies the width of the memory or I/O operations.\r
408   @param  BarIndex              The BAR index of the standard PCI Configuration header to use as the\r
409                                 base address for the memory or I/O operation to perform.\r
410   @param  Offset                The offset within the selected BAR to start the memory or I/O operation.\r
411   @param  Count                 The number of memory or I/O operations to perform.\r
412   @param  Buffer                For read operations, the destination buffer to store the results. For write\r
413                                 operations, the source buffer to write data from.\r
414 \r
415 **/\r
416 STATIC\r
417 EFI_STATUS\r
418 EFIAPI\r
419 PciIoIoWrite (\r
420   IN     EFI_PCI_IO_PROTOCOL          *This,\r
421   IN     EFI_PCI_IO_PROTOCOL_WIDTH    Width,\r
422   IN     UINT8                        BarIndex,\r
423   IN     UINT64                       Offset,\r
424   IN     UINTN                        Count,\r
425   IN OUT VOID                         *Buffer\r
426   )\r
427 {\r
428   ASSERT (FALSE);\r
429   return EFI_UNSUPPORTED;\r
430 }\r
431 \r
432 /**\r
433   Enable a PCI driver to access PCI config space.\r
434 \r
435   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
436   @param  Width                 Signifies the width of the memory or I/O operations.\r
437   @param  Offset                The offset within the selected BAR to start the memory or I/O operation.\r
438   @param  Count                 The number of memory or I/O operations to perform.\r
439   @param  Buffer                For read operations, the destination buffer to store the results. For write\r
440                                 operations, the source buffer to write data from.\r
441 \r
442 **/\r
443 STATIC\r
444 EFI_STATUS\r
445 EFIAPI\r
446 PciIoPciRead (\r
447   IN     EFI_PCI_IO_PROTOCOL        *This,\r
448   IN     EFI_PCI_IO_PROTOCOL_WIDTH  Width,\r
449   IN     UINT32                     Offset,\r
450   IN     UINTN                      Count,\r
451   IN OUT VOID                       *Buffer\r
452   )\r
453 {\r
454   NON_DISCOVERABLE_PCI_DEVICE   *Dev;\r
455   VOID                          *Address;\r
456   UINTN                         Length;\r
457 \r
458   if (Width < 0 || Width >= EfiPciIoWidthMaximum || Buffer == NULL) {\r
459     return EFI_INVALID_PARAMETER;\r
460   }\r
461 \r
462   Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);\r
463   Address = (UINT8 *)&Dev->ConfigSpace + Offset;\r
464   Length = Count << ((UINTN)Width & 0x3);\r
465 \r
466   if (Offset >= sizeof (Dev->ConfigSpace)) {\r
467     ZeroMem (Buffer, Length);\r
468     return EFI_SUCCESS;\r
469   }\r
470 \r
471   if (Offset + Length > sizeof (Dev->ConfigSpace)) {\r
472     //\r
473     // Read all zeroes for config space accesses beyond the first\r
474     // 64 bytes\r
475     //\r
476     Length -= sizeof (Dev->ConfigSpace) - Offset;\r
477     ZeroMem ((UINT8 *)Buffer + sizeof (Dev->ConfigSpace) - Offset, Length);\r
478 \r
479     Count -= Length >> ((UINTN)Width & 0x3);\r
480   }\r
481   return PciIoMemRW (Width, Count, 1, Buffer, 1, Address);\r
482 }\r
483 \r
484 /**\r
485   Enable a PCI driver to access PCI config space.\r
486 \r
487   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
488   @param  Width                 Signifies the width of the memory or I/O operations.\r
489   @param  Offset                The offset within the selected BAR to start the memory or I/O operation.\r
490   @param  Count                 The number of memory or I/O operations to perform.\r
491   @param  Buffer                For read operations, the destination buffer to store the results. For write\r
492                                 operations, the source buffer to write data from\r
493 \r
494   @retval EFI_SUCCESS           The data was read from or written to the PCI controller.\r
495   @retval EFI_UNSUPPORTED       The address range specified by Offset, Width, and Count is not\r
496                                 valid for the PCI BAR specified by BarIndex.\r
497   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
498 \r
499 **/\r
500 STATIC\r
501 EFI_STATUS\r
502 EFIAPI\r
503 PciIoPciWrite (\r
504   IN EFI_PCI_IO_PROTOCOL              *This,\r
505   IN     EFI_PCI_IO_PROTOCOL_WIDTH    Width,\r
506   IN     UINT32                       Offset,\r
507   IN     UINTN                        Count,\r
508   IN OUT VOID                         *Buffer\r
509   )\r
510 {\r
511   NON_DISCOVERABLE_PCI_DEVICE   *Dev;\r
512   VOID                          *Address;\r
513 \r
514   if (Width < 0 || Width >= EfiPciIoWidthMaximum || Buffer == NULL) {\r
515     return EFI_INVALID_PARAMETER;\r
516   }\r
517 \r
518   Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);\r
519   Address = (UINT8 *)&Dev->ConfigSpace + Offset;\r
520 \r
521   if (Offset + (Count << ((UINTN)Width & 0x3)) > sizeof (Dev->ConfigSpace)) {\r
522     return EFI_UNSUPPORTED;\r
523   }\r
524 \r
525   return PciIoMemRW (Width, Count, 1, Address, 1, Buffer);\r
526 }\r
527 \r
528 /**\r
529   Enables a PCI driver to copy one region of PCI memory space to another region of PCI\r
530   memory space.\r
531 \r
532   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
533   @param  Width                 Signifies the width of the memory operations.\r
534   @param  DestBarIndex          The BAR index in the standard PCI Configuration header to use as the\r
535                                 base address for the memory operation to perform.\r
536   @param  DestOffset            The destination offset within the BAR specified by DestBarIndex to\r
537                                 start the memory writes for the copy operation.\r
538   @param  SrcBarIndex           The BAR index in the standard PCI Configuration header to use as the\r
539                                 base address for the memory operation to perform.\r
540   @param  SrcOffset             The source offset within the BAR specified by SrcBarIndex to start\r
541                                 the memory reads for the copy operation.\r
542   @param  Count                 The number of memory operations to perform. Bytes moved is Width\r
543                                 size * Count, starting at DestOffset and SrcOffset.\r
544 \r
545 **/\r
546 STATIC\r
547 EFI_STATUS\r
548 EFIAPI\r
549 PciIoCopyMem (\r
550   IN EFI_PCI_IO_PROTOCOL              *This,\r
551   IN     EFI_PCI_IO_PROTOCOL_WIDTH    Width,\r
552   IN     UINT8                        DestBarIndex,\r
553   IN     UINT64                       DestOffset,\r
554   IN     UINT8                        SrcBarIndex,\r
555   IN     UINT64                       SrcOffset,\r
556   IN     UINTN                        Count\r
557   )\r
558 {\r
559   ASSERT (FALSE);\r
560   return EFI_UNSUPPORTED;\r
561 }\r
562 \r
563 /**\r
564   Provides the PCI controller-specific addresses needed to access system memory.\r
565 \r
566   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
567   @param  Operation             Indicates if the bus master is going to read or write to system memory.\r
568   @param  HostAddress           The system memory address to map to the PCI controller.\r
569   @param  NumberOfBytes         On input the number of bytes to map. On output the number of bytes\r
570                                 that were mapped.\r
571   @param  DeviceAddress         The resulting map address for the bus master PCI controller to use to\r
572                                 access the hosts HostAddress.\r
573   @param  Mapping               A resulting value to pass to Unmap().\r
574 \r
575   @retval EFI_SUCCESS           The range was mapped for the returned NumberOfBytes.\r
576   @retval EFI_UNSUPPORTED       The HostAddress cannot be mapped as a common buffer.\r
577   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
578   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.\r
579   @retval EFI_DEVICE_ERROR      The system hardware could not map the requested address.\r
580 \r
581 **/\r
582 STATIC\r
583 EFI_STATUS\r
584 EFIAPI\r
585 CoherentPciIoMap (\r
586   IN     EFI_PCI_IO_PROTOCOL            *This,\r
587   IN     EFI_PCI_IO_PROTOCOL_OPERATION  Operation,\r
588   IN     VOID                           *HostAddress,\r
589   IN OUT UINTN                          *NumberOfBytes,\r
590   OUT    EFI_PHYSICAL_ADDRESS           *DeviceAddress,\r
591   OUT    VOID                           **Mapping\r
592   )\r
593 {\r
594   NON_DISCOVERABLE_PCI_DEVICE           *Dev;\r
595   EFI_STATUS                            Status;\r
596   NON_DISCOVERABLE_PCI_DEVICE_MAP_INFO  *MapInfo;\r
597 \r
598   if (Operation != EfiPciIoOperationBusMasterRead &&\r
599       Operation != EfiPciIoOperationBusMasterWrite &&\r
600       Operation != EfiPciIoOperationBusMasterCommonBuffer) {\r
601     return EFI_INVALID_PARAMETER;\r
602   }\r
603 \r
604   if (HostAddress   == NULL ||\r
605       NumberOfBytes == NULL ||\r
606       DeviceAddress == NULL ||\r
607       Mapping       == NULL) {\r
608     return EFI_INVALID_PARAMETER;\r
609   }\r
610 \r
611   //\r
612   // If HostAddress exceeds 4 GB, and this device does not support 64-bit DMA\r
613   // addressing, we need to allocate a bounce buffer and copy over the data.\r
614   //\r
615   Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);\r
616   if ((Dev->Attributes & EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE) == 0 &&\r
617       (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress + *NumberOfBytes > SIZE_4GB) {\r
618 \r
619     //\r
620     // Bounce buffering is not possible for consistent mappings\r
621     //\r
622     if (Operation == EfiPciIoOperationBusMasterCommonBuffer) {\r
623       return EFI_UNSUPPORTED;\r
624     }\r
625 \r
626     MapInfo = AllocatePool (sizeof *MapInfo);\r
627     if (MapInfo == NULL) {\r
628       return EFI_OUT_OF_RESOURCES;\r
629     }\r
630 \r
631     MapInfo->AllocAddress = MAX_UINT32;\r
632     MapInfo->HostAddress = HostAddress;\r
633     MapInfo->Operation = Operation;\r
634     MapInfo->NumberOfBytes = *NumberOfBytes;\r
635 \r
636     Status = gBS->AllocatePages (AllocateMaxAddress, EfiBootServicesData,\r
637                     EFI_SIZE_TO_PAGES (MapInfo->NumberOfBytes),\r
638                     &MapInfo->AllocAddress);\r
639     if (EFI_ERROR (Status)) {\r
640       //\r
641       // If we fail here, it is likely because the system has no memory below\r
642       // 4 GB to begin with. There is not much we can do about that other than\r
643       // fail the map request.\r
644       //\r
645       FreePool (MapInfo);\r
646       return EFI_DEVICE_ERROR;\r
647     }\r
648     if (Operation == EfiPciIoOperationBusMasterRead) {\r
649       gBS->CopyMem ((VOID *)(UINTN)MapInfo->AllocAddress, HostAddress,\r
650              *NumberOfBytes);\r
651     }\r
652     *DeviceAddress = MapInfo->AllocAddress;\r
653     *Mapping = MapInfo;\r
654   } else {\r
655     *DeviceAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress;\r
656     *Mapping = NULL;\r
657   }\r
658   return EFI_SUCCESS;\r
659 }\r
660 \r
661 /**\r
662   Completes the Map() operation and releases any corresponding resources.\r
663 \r
664   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
665   @param  Mapping               The mapping value returned from Map().\r
666 \r
667   @retval EFI_SUCCESS           The range was unmapped.\r
668 \r
669 **/\r
670 STATIC\r
671 EFI_STATUS\r
672 EFIAPI\r
673 CoherentPciIoUnmap (\r
674   IN  EFI_PCI_IO_PROTOCOL          *This,\r
675   IN  VOID                         *Mapping\r
676   )\r
677 {\r
678   NON_DISCOVERABLE_PCI_DEVICE_MAP_INFO  *MapInfo;\r
679 \r
680   MapInfo = Mapping;\r
681   if (MapInfo != NULL) {\r
682     if (MapInfo->Operation == EfiPciIoOperationBusMasterWrite) {\r
683       gBS->CopyMem (MapInfo->HostAddress, (VOID *)(UINTN)MapInfo->AllocAddress,\r
684              MapInfo->NumberOfBytes);\r
685     }\r
686     gBS->FreePages (MapInfo->AllocAddress,\r
687            EFI_SIZE_TO_PAGES (MapInfo->NumberOfBytes));\r
688     FreePool (MapInfo);\r
689   }\r
690   return EFI_SUCCESS;\r
691 }\r
692 \r
693 /**\r
694   Allocates pages.\r
695 \r
696   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
697   @param  Type                  This parameter is not used and must be ignored.\r
698   @param  MemoryType            The type of memory to allocate, EfiBootServicesData or\r
699                                 EfiRuntimeServicesData.\r
700   @param  Pages                 The number of pages to allocate.\r
701   @param  HostAddress           A pointer to store the base system memory address of the\r
702                                 allocated range.\r
703   @param  Attributes            The requested bit mask of attributes for the allocated range.\r
704 \r
705   @retval EFI_SUCCESS           The requested memory pages were allocated.\r
706   @retval EFI_UNSUPPORTED       Attributes is unsupported. The only legal attribute bits are\r
707                                 MEMORY_WRITE_COMBINE and MEMORY_CACHED.\r
708   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
709   @retval EFI_OUT_OF_RESOURCES  The memory pages could not be allocated.\r
710 \r
711 **/\r
712 STATIC\r
713 EFI_STATUS\r
714 EFIAPI\r
715 CoherentPciIoAllocateBuffer (\r
716   IN  EFI_PCI_IO_PROTOCOL         *This,\r
717   IN  EFI_ALLOCATE_TYPE           Type,\r
718   IN  EFI_MEMORY_TYPE             MemoryType,\r
719   IN  UINTN                       Pages,\r
720   OUT VOID                        **HostAddress,\r
721   IN  UINT64                      Attributes\r
722   )\r
723 {\r
724   NON_DISCOVERABLE_PCI_DEVICE       *Dev;\r
725   EFI_PHYSICAL_ADDRESS              AllocAddress;\r
726   EFI_ALLOCATE_TYPE                 AllocType;\r
727   EFI_STATUS                        Status;\r
728 \r
729   if ((Attributes & ~(EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE |\r
730                       EFI_PCI_ATTRIBUTE_MEMORY_CACHED)) != 0) {\r
731     return EFI_UNSUPPORTED;\r
732   }\r
733 \r
734   if ((MemoryType != EfiBootServicesData) &&\r
735       (MemoryType != EfiRuntimeServicesData)) {\r
736     return EFI_INVALID_PARAMETER;\r
737   }\r
738 \r
739   //\r
740   // Allocate below 4 GB if the dual address cycle attribute has not\r
741   // been set. If the system has no memory available below 4 GB, there\r
742   // is little we can do except propagate the error.\r
743   //\r
744   Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);\r
745   if ((Dev->Attributes & EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE) == 0) {\r
746     AllocAddress = MAX_UINT32;\r
747     AllocType = AllocateMaxAddress;\r
748   } else {\r
749     AllocType = AllocateAnyPages;\r
750   }\r
751 \r
752   Status = gBS->AllocatePages (AllocType, MemoryType, Pages, &AllocAddress);\r
753   if (!EFI_ERROR (Status)) {\r
754     *HostAddress = (VOID *)(UINTN)AllocAddress;\r
755   }\r
756   return Status;\r
757 }\r
758 \r
759 /**\r
760   Frees memory that was allocated in function CoherentPciIoAllocateBuffer ().\r
761 \r
762   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
763   @param  Pages                 The number of pages to free.\r
764   @param  HostAddress           The base system memory address of the allocated range.\r
765 \r
766   @retval EFI_SUCCESS           The requested memory pages were freed.\r
767 \r
768 **/\r
769 STATIC\r
770 EFI_STATUS\r
771 EFIAPI\r
772 CoherentPciIoFreeBuffer (\r
773   IN  EFI_PCI_IO_PROTOCOL         *This,\r
774   IN  UINTN                       Pages,\r
775   IN  VOID                        *HostAddress\r
776   )\r
777 {\r
778   FreePages (HostAddress, Pages);\r
779   return EFI_SUCCESS;\r
780 }\r
781 \r
782 /**\r
783   Frees memory that was allocated in function NonCoherentPciIoAllocateBuffer ().\r
784 \r
785   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
786   @param  Pages                 The number of pages to free.\r
787   @param  HostAddress           The base system memory address of the allocated range.\r
788 \r
789   @retval EFI_SUCCESS           The requested memory pages were freed.\r
790   @retval others                The operation contain some errors.\r
791 \r
792 **/\r
793 STATIC\r
794 EFI_STATUS\r
795 EFIAPI\r
796 NonCoherentPciIoFreeBuffer (\r
797   IN  EFI_PCI_IO_PROTOCOL         *This,\r
798   IN  UINTN                       Pages,\r
799   IN  VOID                        *HostAddress\r
800   )\r
801 {\r
802   NON_DISCOVERABLE_PCI_DEVICE                   *Dev;\r
803   LIST_ENTRY                                    *Entry;\r
804   EFI_STATUS                                    Status;\r
805   NON_DISCOVERABLE_DEVICE_UNCACHED_ALLOCATION   *Alloc;\r
806   BOOLEAN                                       Found;\r
807 \r
808   Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);\r
809 \r
810   Found = FALSE;\r
811   Alloc = NULL;\r
812 \r
813   //\r
814   // Find the uncached allocation list entry associated\r
815   // with this allocation\r
816   //\r
817   for (Entry = Dev->UncachedAllocationList.ForwardLink;\r
818        Entry != &Dev->UncachedAllocationList;\r
819        Entry = Entry->ForwardLink) {\r
820 \r
821     Alloc = BASE_CR (Entry, NON_DISCOVERABLE_DEVICE_UNCACHED_ALLOCATION, List);\r
822     if (Alloc->HostAddress == HostAddress && Alloc->NumPages == Pages) {\r
823       //\r
824       // We are freeing the exact allocation we were given\r
825       // before by AllocateBuffer()\r
826       //\r
827       Found = TRUE;\r
828       break;\r
829     }\r
830   }\r
831 \r
832   if (!Found) {\r
833     ASSERT_EFI_ERROR (EFI_NOT_FOUND);\r
834     return EFI_NOT_FOUND;\r
835   }\r
836 \r
837   RemoveEntryList (&Alloc->List);\r
838 \r
839   Status = gDS->SetMemorySpaceAttributes (\r
840                   (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress,\r
841                   EFI_PAGES_TO_SIZE (Pages),\r
842                   Alloc->Attributes);\r
843   if (EFI_ERROR (Status)) {\r
844     goto FreeAlloc;\r
845   }\r
846 \r
847   //\r
848   // If we fail to restore the original attributes, it is better to leak the\r
849   // memory than to return it to the heap\r
850   //\r
851   FreePages (HostAddress, Pages);\r
852 \r
853 FreeAlloc:\r
854   FreePool (Alloc);\r
855   return Status;\r
856 }\r
857 \r
858 /**\r
859   Allocates pages.\r
860 \r
861   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
862   @param  Type                  This parameter is not used and must be ignored.\r
863   @param  MemoryType            The type of memory to allocate, EfiBootServicesData or\r
864                                 EfiRuntimeServicesData.\r
865   @param  Pages                 The number of pages to allocate.\r
866   @param  HostAddress           A pointer to store the base system memory address of the\r
867                                 allocated range.\r
868   @param  Attributes            The requested bit mask of attributes for the allocated range.\r
869 \r
870   @retval EFI_SUCCESS           The requested memory pages were allocated.\r
871   @retval EFI_UNSUPPORTED       Attributes is unsupported. The only legal attribute bits are\r
872                                 MEMORY_WRITE_COMBINE and MEMORY_CACHED.\r
873   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
874   @retval EFI_OUT_OF_RESOURCES  The memory pages could not be allocated.\r
875 \r
876 **/\r
877 STATIC\r
878 EFI_STATUS\r
879 EFIAPI\r
880 NonCoherentPciIoAllocateBuffer (\r
881   IN  EFI_PCI_IO_PROTOCOL         *This,\r
882   IN  EFI_ALLOCATE_TYPE           Type,\r
883   IN  EFI_MEMORY_TYPE             MemoryType,\r
884   IN  UINTN                       Pages,\r
885   OUT VOID                        **HostAddress,\r
886   IN  UINT64                      Attributes\r
887   )\r
888 {\r
889   NON_DISCOVERABLE_PCI_DEVICE                 *Dev;\r
890   EFI_GCD_MEMORY_SPACE_DESCRIPTOR             GcdDescriptor;\r
891   EFI_STATUS                                  Status;\r
892   UINT64                                      MemType;\r
893   NON_DISCOVERABLE_DEVICE_UNCACHED_ALLOCATION *Alloc;\r
894   VOID                                        *AllocAddress;\r
895 \r
896   if (HostAddress == NULL) {\r
897     return EFI_INVALID_PARAMETER;\r
898   }\r
899 \r
900   Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);\r
901 \r
902   Status = CoherentPciIoAllocateBuffer (This, Type, MemoryType, Pages,\r
903              &AllocAddress, Attributes);\r
904   if (EFI_ERROR (Status)) {\r
905     return Status;\r
906   }\r
907 \r
908   Status = gDS->GetMemorySpaceDescriptor (\r
909                   (EFI_PHYSICAL_ADDRESS)(UINTN)AllocAddress,\r
910                   &GcdDescriptor);\r
911   if (EFI_ERROR (Status)) {\r
912     goto FreeBuffer;\r
913   }\r
914 \r
915   if ((GcdDescriptor.Capabilities & (EFI_MEMORY_WC | EFI_MEMORY_UC)) == 0) {\r
916     Status = EFI_UNSUPPORTED;\r
917     goto FreeBuffer;\r
918   }\r
919 \r
920   //\r
921   // Set the preferred memory attributes\r
922   //\r
923   if ((Attributes & EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE) != 0 ||\r
924       (GcdDescriptor.Capabilities & EFI_MEMORY_UC) == 0) {\r
925     //\r
926     // Use write combining if it was requested, or if it is the only\r
927     // type supported by the region.\r
928     //\r
929     MemType = EFI_MEMORY_WC;\r
930   } else {\r
931     MemType = EFI_MEMORY_UC;\r
932   }\r
933 \r
934   Alloc = AllocatePool (sizeof *Alloc);\r
935   if (Alloc == NULL) {\r
936     goto FreeBuffer;\r
937   }\r
938 \r
939   Alloc->HostAddress = AllocAddress;\r
940   Alloc->NumPages = Pages;\r
941   Alloc->Attributes = GcdDescriptor.Attributes;\r
942 \r
943   //\r
944   // Record this allocation in the linked list, so we\r
945   // can restore the memory space attributes later\r
946   //\r
947   InsertHeadList (&Dev->UncachedAllocationList, &Alloc->List);\r
948 \r
949   Status = gDS->SetMemorySpaceAttributes (\r
950                   (EFI_PHYSICAL_ADDRESS)(UINTN)AllocAddress,\r
951                   EFI_PAGES_TO_SIZE (Pages),\r
952                   MemType);\r
953   if (EFI_ERROR (Status)) {\r
954     goto RemoveList;\r
955   }\r
956 \r
957   Status = mCpu->FlushDataCache (\r
958                    mCpu,\r
959                    (EFI_PHYSICAL_ADDRESS)(UINTN)AllocAddress,\r
960                    EFI_PAGES_TO_SIZE (Pages),\r
961                    EfiCpuFlushTypeInvalidate);\r
962   if (EFI_ERROR (Status)) {\r
963     goto RemoveList;\r
964   }\r
965 \r
966   *HostAddress = AllocAddress;\r
967 \r
968   return EFI_SUCCESS;\r
969 \r
970 RemoveList:\r
971   RemoveEntryList (&Alloc->List);\r
972   FreePool (Alloc);\r
973 \r
974 FreeBuffer:\r
975   CoherentPciIoFreeBuffer (This, Pages, AllocAddress);\r
976   return Status;\r
977 }\r
978 \r
979 /**\r
980   Provides the PCI controller-specific addresses needed to access system memory.\r
981 \r
982   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
983   @param  Operation             Indicates if the bus master is going to read or write to system memory.\r
984   @param  HostAddress           The system memory address to map to the PCI controller.\r
985   @param  NumberOfBytes         On input the number of bytes to map. On output the number of bytes\r
986                                 that were mapped.\r
987   @param  DeviceAddress         The resulting map address for the bus master PCI controller to use to\r
988                                 access the hosts HostAddress.\r
989   @param  Mapping               A resulting value to pass to Unmap().\r
990 \r
991   @retval EFI_SUCCESS           The range was mapped for the returned NumberOfBytes.\r
992   @retval EFI_UNSUPPORTED       The HostAddress cannot be mapped as a common buffer.\r
993   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
994   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.\r
995   @retval EFI_DEVICE_ERROR      The system hardware could not map the requested address.\r
996 \r
997 **/\r
998 STATIC\r
999 EFI_STATUS\r
1000 EFIAPI\r
1001 NonCoherentPciIoMap (\r
1002   IN     EFI_PCI_IO_PROTOCOL            *This,\r
1003   IN     EFI_PCI_IO_PROTOCOL_OPERATION  Operation,\r
1004   IN     VOID                           *HostAddress,\r
1005   IN OUT UINTN                          *NumberOfBytes,\r
1006   OUT    EFI_PHYSICAL_ADDRESS           *DeviceAddress,\r
1007   OUT    VOID                           **Mapping\r
1008   )\r
1009 {\r
1010   NON_DISCOVERABLE_PCI_DEVICE           *Dev;\r
1011   EFI_STATUS                            Status;\r
1012   NON_DISCOVERABLE_PCI_DEVICE_MAP_INFO  *MapInfo;\r
1013   UINTN                                 AlignMask;\r
1014   VOID                                  *AllocAddress;\r
1015   EFI_GCD_MEMORY_SPACE_DESCRIPTOR       GcdDescriptor;\r
1016   BOOLEAN                               Bounce;\r
1017 \r
1018   if (HostAddress   == NULL ||\r
1019       NumberOfBytes == NULL ||\r
1020       DeviceAddress == NULL ||\r
1021       Mapping       == NULL) {\r
1022     return EFI_INVALID_PARAMETER;\r
1023   }\r
1024 \r
1025   if (Operation != EfiPciIoOperationBusMasterRead &&\r
1026       Operation != EfiPciIoOperationBusMasterWrite &&\r
1027       Operation != EfiPciIoOperationBusMasterCommonBuffer) {\r
1028     return EFI_INVALID_PARAMETER;\r
1029   }\r
1030 \r
1031   MapInfo = AllocatePool (sizeof *MapInfo);\r
1032   if (MapInfo == NULL) {\r
1033     return EFI_OUT_OF_RESOURCES;\r
1034   }\r
1035 \r
1036   MapInfo->HostAddress = HostAddress;\r
1037   MapInfo->Operation = Operation;\r
1038   MapInfo->NumberOfBytes = *NumberOfBytes;\r
1039 \r
1040   Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);\r
1041 \r
1042   //\r
1043   // If this device does not support 64-bit DMA addressing, we need to allocate\r
1044   // a bounce buffer and copy over the data in case HostAddress >= 4 GB.\r
1045   //\r
1046   Bounce = ((Dev->Attributes & EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE) == 0 &&\r
1047             (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress + *NumberOfBytes > SIZE_4GB);\r
1048 \r
1049   if (!Bounce) {\r
1050     switch (Operation) {\r
1051     case EfiPciIoOperationBusMasterRead:\r
1052     case EfiPciIoOperationBusMasterWrite:\r
1053       //\r
1054       // For streaming DMA, it is sufficient if the buffer is aligned to\r
1055       // the CPUs DMA buffer alignment.\r
1056       //\r
1057       AlignMask = mCpu->DmaBufferAlignment - 1;\r
1058       if ((((UINTN) HostAddress | *NumberOfBytes) & AlignMask) == 0) {\r
1059         break;\r
1060       }\r
1061       // fall through\r
1062 \r
1063     case EfiPciIoOperationBusMasterCommonBuffer:\r
1064       //\r
1065       // Check whether the host address refers to an uncached mapping.\r
1066       //\r
1067       Status = gDS->GetMemorySpaceDescriptor (\r
1068                       (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress,\r
1069                       &GcdDescriptor);\r
1070       if (EFI_ERROR (Status) ||\r
1071           (GcdDescriptor.Attributes & (EFI_MEMORY_WB|EFI_MEMORY_WT)) != 0) {\r
1072         Bounce = TRUE;\r
1073       }\r
1074       break;\r
1075 \r
1076     default:\r
1077       ASSERT (FALSE);\r
1078     }\r
1079   }\r
1080 \r
1081   if (Bounce) {\r
1082     if (Operation == EfiPciIoOperationBusMasterCommonBuffer) {\r
1083       Status = EFI_DEVICE_ERROR;\r
1084       goto FreeMapInfo;\r
1085     }\r
1086 \r
1087     Status = NonCoherentPciIoAllocateBuffer (This, AllocateAnyPages,\r
1088                EfiBootServicesData, EFI_SIZE_TO_PAGES (MapInfo->NumberOfBytes),\r
1089                &AllocAddress, EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE);\r
1090     if (EFI_ERROR (Status)) {\r
1091       goto FreeMapInfo;\r
1092     }\r
1093     MapInfo->AllocAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocAddress;\r
1094     if (Operation == EfiPciIoOperationBusMasterRead) {\r
1095       gBS->CopyMem (AllocAddress, HostAddress, *NumberOfBytes);\r
1096     }\r
1097     *DeviceAddress = MapInfo->AllocAddress;\r
1098   } else {\r
1099     MapInfo->AllocAddress = 0;\r
1100     *DeviceAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress;\r
1101 \r
1102     //\r
1103     // We are not using a bounce buffer: the mapping is sufficiently\r
1104     // aligned to allow us to simply flush the caches. Note that cleaning\r
1105     // the caches is necessary for both data directions:\r
1106     // - for bus master read, we want the latest data to be present\r
1107     //   in main memory\r
1108     // - for bus master write, we don't want any stale dirty cachelines that\r
1109     //   may be written back unexpectedly, and clobber the data written to\r
1110     //   main memory by the device.\r
1111     //\r
1112     mCpu->FlushDataCache (mCpu, (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress,\r
1113             *NumberOfBytes, EfiCpuFlushTypeWriteBack);\r
1114   }\r
1115 \r
1116   *Mapping = MapInfo;\r
1117   return EFI_SUCCESS;\r
1118 \r
1119 FreeMapInfo:\r
1120   FreePool (MapInfo);\r
1121 \r
1122   return Status;\r
1123 }\r
1124 \r
1125 /**\r
1126   Completes the Map() operation and releases any corresponding resources.\r
1127 \r
1128   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
1129   @param  Mapping               The mapping value returned from Map().\r
1130 \r
1131   @retval EFI_SUCCESS           The range was unmapped.\r
1132 \r
1133 **/\r
1134 STATIC\r
1135 EFI_STATUS\r
1136 EFIAPI\r
1137 NonCoherentPciIoUnmap (\r
1138   IN  EFI_PCI_IO_PROTOCOL          *This,\r
1139   IN  VOID                         *Mapping\r
1140   )\r
1141 {\r
1142   NON_DISCOVERABLE_PCI_DEVICE_MAP_INFO  *MapInfo;\r
1143 \r
1144   if (Mapping == NULL) {\r
1145     return EFI_DEVICE_ERROR;\r
1146   }\r
1147 \r
1148   MapInfo = Mapping;\r
1149   if (MapInfo->AllocAddress != 0) {\r
1150     //\r
1151     // We are using a bounce buffer: copy back the data if necessary,\r
1152     // and free the buffer.\r
1153     //\r
1154     if (MapInfo->Operation == EfiPciIoOperationBusMasterWrite) {\r
1155       gBS->CopyMem (MapInfo->HostAddress, (VOID *)(UINTN)MapInfo->AllocAddress,\r
1156              MapInfo->NumberOfBytes);\r
1157     }\r
1158     NonCoherentPciIoFreeBuffer (This,\r
1159       EFI_SIZE_TO_PAGES (MapInfo->NumberOfBytes),\r
1160       (VOID *)(UINTN)MapInfo->AllocAddress);\r
1161   } else {\r
1162     //\r
1163     // We are *not* using a bounce buffer: if this is a bus master write,\r
1164     // we have to invalidate the caches so the CPU will see the uncached\r
1165     // data written by the device.\r
1166     //\r
1167     if (MapInfo->Operation == EfiPciIoOperationBusMasterWrite) {\r
1168       mCpu->FlushDataCache (mCpu,\r
1169               (EFI_PHYSICAL_ADDRESS)(UINTN)MapInfo->HostAddress,\r
1170               MapInfo->NumberOfBytes, EfiCpuFlushTypeInvalidate);\r
1171     }\r
1172   }\r
1173   FreePool (MapInfo);\r
1174   return EFI_SUCCESS;\r
1175 }\r
1176 \r
1177 /**\r
1178   Flushes all PCI posted write transactions from a PCI host bridge to system memory.\r
1179 \r
1180   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
1181 \r
1182 **/\r
1183 STATIC\r
1184 EFI_STATUS\r
1185 EFIAPI\r
1186 PciIoFlush (\r
1187   IN EFI_PCI_IO_PROTOCOL          *This\r
1188   )\r
1189 {\r
1190   return EFI_SUCCESS;\r
1191 }\r
1192 \r
1193 /**\r
1194   Retrieves this PCI controller's current PCI bus number, device number, and function number.\r
1195 \r
1196   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
1197   @param  SegmentNumber         The PCI controller's current PCI segment number.\r
1198   @param  BusNumber             The PCI controller's current PCI bus number.\r
1199   @param  DeviceNumber          The PCI controller's current PCI device number.\r
1200   @param  FunctionNumber        The PCI controller's current PCI function number.\r
1201 \r
1202   @retval EFI_SUCCESS           The PCI controller location was returned.\r
1203   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
1204 \r
1205 **/\r
1206 STATIC\r
1207 EFI_STATUS\r
1208 EFIAPI\r
1209 PciIoGetLocation (\r
1210   IN   EFI_PCI_IO_PROTOCOL  *This,\r
1211   OUT  UINTN                *SegmentNumber,\r
1212   OUT  UINTN                *BusNumber,\r
1213   OUT  UINTN                *DeviceNumber,\r
1214   OUT  UINTN                *FunctionNumber\r
1215   )\r
1216 {\r
1217   NON_DISCOVERABLE_PCI_DEVICE         *Dev;\r
1218 \r
1219   if (SegmentNumber == NULL ||\r
1220       BusNumber == NULL ||\r
1221       DeviceNumber == NULL ||\r
1222       FunctionNumber == NULL) {\r
1223     return EFI_INVALID_PARAMETER;\r
1224   }\r
1225 \r
1226   Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);\r
1227 \r
1228   *SegmentNumber  = 0xff;\r
1229   *BusNumber      = Dev->UniqueId >> 5;\r
1230   *DeviceNumber   = Dev->UniqueId & 0x1f;\r
1231   *FunctionNumber = 0;\r
1232 \r
1233   return EFI_SUCCESS;\r
1234 }\r
1235 \r
1236 /**\r
1237   Performs an operation on the attributes that this PCI controller supports. The operations include\r
1238   getting the set of supported attributes, retrieving the current attributes, setting the current\r
1239   attributes, enabling attributes, and disabling attributes.\r
1240 \r
1241   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
1242   @param  Operation             The operation to perform on the attributes for this PCI controller.\r
1243   @param  Attributes            The mask of attributes that are used for Set, Enable, and Disable\r
1244                                 operations.\r
1245   @param  Result                A pointer to the result mask of attributes that are returned for the Get\r
1246                                 and Supported operations.\r
1247 \r
1248   @retval EFI_SUCCESS           The operation on the PCI controller's attributes was completed.\r
1249   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
1250   @retval EFI_UNSUPPORTED       one or more of the bits set in\r
1251                                 Attributes are not supported by this PCI controller or one of\r
1252                                 its parent bridges when Operation is Set, Enable or Disable.\r
1253 \r
1254 **/\r
1255 STATIC\r
1256 EFI_STATUS\r
1257 EFIAPI\r
1258 PciIoAttributes (\r
1259   IN  EFI_PCI_IO_PROTOCOL                      *This,\r
1260   IN  EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION  Operation,\r
1261   IN  UINT64                                   Attributes,\r
1262   OUT UINT64                                   *Result OPTIONAL\r
1263   )\r
1264 {\r
1265   NON_DISCOVERABLE_PCI_DEVICE   *Dev;\r
1266   BOOLEAN                       Enable;\r
1267 \r
1268   #define DEV_SUPPORTED_ATTRIBUTES \\r
1269     (EFI_PCI_DEVICE_ENABLE | EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE)\r
1270 \r
1271   Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);\r
1272 \r
1273   if ((Attributes & (~(DEV_SUPPORTED_ATTRIBUTES))) != 0) {\r
1274     return EFI_UNSUPPORTED;\r
1275   }\r
1276 \r
1277   Enable = FALSE;\r
1278   switch (Operation) {\r
1279   case EfiPciIoAttributeOperationGet:\r
1280     if (Result == NULL) {\r
1281       return EFI_INVALID_PARAMETER;\r
1282     }\r
1283     *Result = Dev->Attributes;\r
1284     break;\r
1285 \r
1286   case EfiPciIoAttributeOperationSupported:\r
1287     if (Result == NULL) {\r
1288       return EFI_INVALID_PARAMETER;\r
1289     }\r
1290     *Result = DEV_SUPPORTED_ATTRIBUTES;\r
1291     break;\r
1292 \r
1293   case EfiPciIoAttributeOperationEnable:\r
1294     Attributes |= Dev->Attributes;\r
1295   case EfiPciIoAttributeOperationSet:\r
1296     Enable = ((~Dev->Attributes & Attributes) & EFI_PCI_DEVICE_ENABLE) != 0;\r
1297     Dev->Attributes = Attributes;\r
1298     break;\r
1299 \r
1300   case EfiPciIoAttributeOperationDisable:\r
1301     Dev->Attributes &= ~Attributes;\r
1302     break;\r
1303 \r
1304   default:\r
1305     return EFI_INVALID_PARAMETER;\r
1306   };\r
1307 \r
1308   //\r
1309   // If we're setting any of the EFI_PCI_DEVICE_ENABLE bits, perform\r
1310   // the device specific initialization now.\r
1311   //\r
1312   if (Enable && !Dev->Enabled && Dev->Device->Initialize != NULL) {\r
1313     Dev->Device->Initialize (Dev->Device);\r
1314     Dev->Enabled = TRUE;\r
1315   }\r
1316   return EFI_SUCCESS;\r
1317 }\r
1318 \r
1319 /**\r
1320   Gets the attributes that this PCI controller supports setting on a BAR using\r
1321   SetBarAttributes(), and retrieves the list of resource descriptors for a BAR.\r
1322 \r
1323   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
1324   @param  BarIndex              The BAR index of the standard PCI Configuration header to use as the\r
1325                                 base address for resource range. The legal range for this field is 0..5.\r
1326   @param  Supports              A pointer to the mask of attributes that this PCI controller supports\r
1327                                 setting for this BAR with SetBarAttributes().\r
1328   @param  Resources             A pointer to the ACPI 2.0 resource descriptors that describe the current\r
1329                                 configuration of this BAR of the PCI controller.\r
1330 \r
1331   @retval EFI_SUCCESS           If Supports is not NULL, then the attributes that the PCI\r
1332                                 controller supports are returned in Supports. If Resources\r
1333                                 is not NULL, then the ACPI 2.0 resource descriptors that the PCI\r
1334                                 controller is currently using are returned in Resources.\r
1335   @retval EFI_INVALID_PARAMETER Both Supports and Attributes are NULL.\r
1336   @retval EFI_UNSUPPORTED       BarIndex not valid for this PCI controller.\r
1337   @retval EFI_OUT_OF_RESOURCES  There are not enough resources available to allocate\r
1338                                 Resources.\r
1339 \r
1340 **/\r
1341 STATIC\r
1342 EFI_STATUS\r
1343 EFIAPI\r
1344 PciIoGetBarAttributes (\r
1345   IN EFI_PCI_IO_PROTOCOL             *This,\r
1346   IN  UINT8                          BarIndex,\r
1347   OUT UINT64                         *Supports OPTIONAL,\r
1348   OUT VOID                           **Resources OPTIONAL\r
1349   )\r
1350 {\r
1351   NON_DISCOVERABLE_PCI_DEVICE       *Dev;\r
1352   EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;\r
1353   EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *BarDesc;\r
1354   EFI_ACPI_END_TAG_DESCRIPTOR       *End;\r
1355   EFI_STATUS                        Status;\r
1356 \r
1357   if (Supports == NULL && Resources == NULL) {\r
1358     return EFI_INVALID_PARAMETER;\r
1359   }\r
1360 \r
1361   Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);\r
1362 \r
1363   Status = GetBarResource (Dev, BarIndex, &BarDesc);\r
1364   if (EFI_ERROR (Status)) {\r
1365     return Status;\r
1366   }\r
1367 \r
1368   //\r
1369   // Don't expose any configurable attributes for our emulated BAR\r
1370   //\r
1371   if (Supports != NULL) {\r
1372     *Supports = 0;\r
1373   }\r
1374 \r
1375   if (Resources != NULL) {\r
1376     Descriptor = AllocatePool (sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) +\r
1377                                sizeof (EFI_ACPI_END_TAG_DESCRIPTOR));\r
1378     if (Descriptor == NULL) {\r
1379       return EFI_OUT_OF_RESOURCES;\r
1380     }\r
1381 \r
1382     CopyMem (Descriptor, BarDesc, sizeof *Descriptor);\r
1383 \r
1384     End           = (EFI_ACPI_END_TAG_DESCRIPTOR *) (Descriptor + 1);\r
1385     End->Desc     = ACPI_END_TAG_DESCRIPTOR;\r
1386     End->Checksum = 0;\r
1387 \r
1388     *Resources = Descriptor;\r
1389   }\r
1390   return EFI_SUCCESS;\r
1391 }\r
1392 \r
1393 /**\r
1394   Sets the attributes for a range of a BAR on a PCI controller.\r
1395 \r
1396   @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
1397   @param  Attributes            The mask of attributes to set for the resource range specified by\r
1398                                 BarIndex, Offset, and Length.\r
1399   @param  BarIndex              The BAR index of the standard PCI Configuration header to use as the\r
1400                                 base address for resource range. The legal range for this field is 0..5.\r
1401   @param  Offset                A pointer to the BAR relative base address of the resource range to be\r
1402                                 modified by the attributes specified by Attributes.\r
1403   @param  Length                A pointer to the length of the resource range to be modified by the\r
1404                                 attributes specified by Attributes.\r
1405 **/\r
1406 STATIC\r
1407 EFI_STATUS\r
1408 EFIAPI\r
1409 PciIoSetBarAttributes (\r
1410   IN     EFI_PCI_IO_PROTOCOL          *This,\r
1411   IN     UINT64                       Attributes,\r
1412   IN     UINT8                        BarIndex,\r
1413   IN OUT UINT64                       *Offset,\r
1414   IN OUT UINT64                       *Length\r
1415   )\r
1416 {\r
1417   ASSERT (FALSE);\r
1418   return EFI_UNSUPPORTED;\r
1419 }\r
1420 \r
1421 STATIC CONST EFI_PCI_IO_PROTOCOL PciIoTemplate =\r
1422 {\r
1423   PciIoPollMem,\r
1424   PciIoPollIo,\r
1425   { PciIoMemRead, PciIoMemWrite },\r
1426   { PciIoIoRead,  PciIoIoWrite },\r
1427   { PciIoPciRead, PciIoPciWrite },\r
1428   PciIoCopyMem,\r
1429   CoherentPciIoMap,\r
1430   CoherentPciIoUnmap,\r
1431   CoherentPciIoAllocateBuffer,\r
1432   CoherentPciIoFreeBuffer,\r
1433   PciIoFlush,\r
1434   PciIoGetLocation,\r
1435   PciIoAttributes,\r
1436   PciIoGetBarAttributes,\r
1437   PciIoSetBarAttributes,\r
1438   0,\r
1439   0\r
1440 };\r
1441 \r
1442 /**\r
1443   Initialize PciIo Protocol.\r
1444 \r
1445   @param  Dev      Point to NON_DISCOVERABLE_PCI_DEVICE instance.\r
1446 \r
1447 **/\r
1448 VOID\r
1449 InitializePciIoProtocol (\r
1450   NON_DISCOVERABLE_PCI_DEVICE     *Dev\r
1451   )\r
1452 {\r
1453   EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR   *Desc;\r
1454   INTN                                Idx;\r
1455 \r
1456   InitializeListHead (&Dev->UncachedAllocationList);\r
1457 \r
1458   Dev->ConfigSpace.Hdr.VendorId = PCI_ID_VENDOR_UNKNOWN;\r
1459   Dev->ConfigSpace.Hdr.DeviceId = PCI_ID_DEVICE_DONTCARE;\r
1460 \r
1461   // Copy protocol structure\r
1462   CopyMem(&Dev->PciIo, &PciIoTemplate, sizeof PciIoTemplate);\r
1463 \r
1464   if (Dev->Device->DmaType == NonDiscoverableDeviceDmaTypeNonCoherent) {\r
1465     Dev->PciIo.AllocateBuffer   = NonCoherentPciIoAllocateBuffer;\r
1466     Dev->PciIo.FreeBuffer       = NonCoherentPciIoFreeBuffer;\r
1467     Dev->PciIo.Map              = NonCoherentPciIoMap;\r
1468     Dev->PciIo.Unmap            = NonCoherentPciIoUnmap;\r
1469   }\r
1470 \r
1471   if (CompareGuid (Dev->Device->Type, &gEdkiiNonDiscoverableAhciDeviceGuid)) {\r
1472     Dev->ConfigSpace.Hdr.ClassCode[0] = PCI_IF_MASS_STORAGE_AHCI;\r
1473     Dev->ConfigSpace.Hdr.ClassCode[1] = PCI_CLASS_MASS_STORAGE_SATADPA;\r
1474     Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_MASS_STORAGE;\r
1475     Dev->BarOffset = 5;\r
1476   } else if (CompareGuid (Dev->Device->Type,\r
1477                           &gEdkiiNonDiscoverableEhciDeviceGuid)) {\r
1478     Dev->ConfigSpace.Hdr.ClassCode[0] = PCI_IF_EHCI;\r
1479     Dev->ConfigSpace.Hdr.ClassCode[1] = PCI_CLASS_SERIAL_USB;\r
1480     Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_SERIAL;\r
1481     Dev->BarOffset = 0;\r
1482   } else if (CompareGuid (Dev->Device->Type,\r
1483                           &gEdkiiNonDiscoverableNvmeDeviceGuid)) {\r
1484     Dev->ConfigSpace.Hdr.ClassCode[0] = 0x2; // PCI_IF_NVMHCI\r
1485     Dev->ConfigSpace.Hdr.ClassCode[1] = 0x8; // PCI_CLASS_MASS_STORAGE_NVM\r
1486     Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_MASS_STORAGE;\r
1487     Dev->BarOffset = 0;\r
1488   } else if (CompareGuid (Dev->Device->Type,\r
1489                           &gEdkiiNonDiscoverableOhciDeviceGuid)) {\r
1490     Dev->ConfigSpace.Hdr.ClassCode[0] = PCI_IF_OHCI;\r
1491     Dev->ConfigSpace.Hdr.ClassCode[1] = PCI_CLASS_SERIAL_USB;\r
1492     Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_SERIAL;\r
1493     Dev->BarOffset = 0;\r
1494   } else if (CompareGuid (Dev->Device->Type,\r
1495                           &gEdkiiNonDiscoverableSdhciDeviceGuid)) {\r
1496     Dev->ConfigSpace.Hdr.ClassCode[0] = 0x0; // don't care\r
1497     Dev->ConfigSpace.Hdr.ClassCode[1] = PCI_SUBCLASS_SD_HOST_CONTROLLER;\r
1498     Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_SYSTEM_PERIPHERAL;\r
1499     Dev->BarOffset = 0;\r
1500   } else if (CompareGuid (Dev->Device->Type,\r
1501                           &gEdkiiNonDiscoverableXhciDeviceGuid)) {\r
1502     Dev->ConfigSpace.Hdr.ClassCode[0] = PCI_IF_XHCI;\r
1503     Dev->ConfigSpace.Hdr.ClassCode[1] = PCI_CLASS_SERIAL_USB;\r
1504     Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_SERIAL;\r
1505     Dev->BarOffset = 0;\r
1506   } else if (CompareGuid (Dev->Device->Type,\r
1507                           &gEdkiiNonDiscoverableUhciDeviceGuid)) {\r
1508     Dev->ConfigSpace.Hdr.ClassCode[0] = PCI_IF_UHCI;\r
1509     Dev->ConfigSpace.Hdr.ClassCode[1] = PCI_CLASS_SERIAL_USB;\r
1510     Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_SERIAL;\r
1511     Dev->BarOffset = 0;\r
1512   } else if (CompareGuid (Dev->Device->Type,\r
1513                           &gEdkiiNonDiscoverableUfsDeviceGuid)) {\r
1514     Dev->ConfigSpace.Hdr.ClassCode[0] = 0x0; // don't care\r
1515     Dev->ConfigSpace.Hdr.ClassCode[1] = 0x9; // UFS controller subclass;\r
1516     Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_MASS_STORAGE;\r
1517     Dev->BarOffset = 0;\r
1518   } else {\r
1519     ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);\r
1520   }\r
1521 \r
1522   //\r
1523   // Iterate over the resources to populate the virtual BARs\r
1524   //\r
1525   Idx = Dev->BarOffset;\r
1526   for (Desc = Dev->Device->Resources, Dev->BarCount = 0;\r
1527        Desc->Desc != ACPI_END_TAG_DESCRIPTOR;\r
1528        Desc = (VOID *)((UINT8 *)Desc + Desc->Len + 3)) {\r
1529 \r
1530     ASSERT (Desc->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR);\r
1531     ASSERT (Desc->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM);\r
1532 \r
1533     if (Idx >= PCI_MAX_BARS ||\r
1534         (Idx == PCI_MAX_BARS - 1 && Desc->AddrSpaceGranularity == 64)) {\r
1535       DEBUG ((DEBUG_ERROR,\r
1536         "%a: resource count exceeds number of emulated BARs\n",\r
1537         __FUNCTION__));\r
1538       ASSERT (FALSE);\r
1539       break;\r
1540     }\r
1541 \r
1542     Dev->ConfigSpace.Device.Bar[Idx] = (UINT32)Desc->AddrRangeMin;\r
1543     Dev->BarCount++;\r
1544 \r
1545     if (Desc->AddrSpaceGranularity == 64) {\r
1546       Dev->ConfigSpace.Device.Bar[Idx] |= 0x4;\r
1547       Dev->ConfigSpace.Device.Bar[++Idx] = (UINT32)RShiftU64 (\r
1548                                                      Desc->AddrRangeMin, 32);\r
1549     }\r
1550   }\r
1551 }\r