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