]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePciDeviceIo.c
MdeModulePkg/NonDiscoverablePciDeviceDxe: add support for non-coherent DMA
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / NonDiscoverablePciDeviceDxe / NonDiscoverablePciDeviceIo.c
CommitLineData
a42e6d44
AB
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 This program and the accompanying materials\r
7 are licensed and made available under the terms and conditions of the BSD License\r
8 which accompanies this distribution. The full text of the license may be found at\r
9 http://opensource.org/licenses/bsd-license.php\r
10\r
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13\r
14**/\r
15\r
16#include "NonDiscoverablePciDeviceIo.h"\r
17\r
16296a12
AB
18#include <Library/DxeServicesTableLib.h>\r
19\r
a42e6d44
AB
20#include <IndustryStandard/Acpi.h>\r
21\r
22#include <Protocol/PciRootBridgeIo.h>\r
23\r
24typedef struct {\r
25 EFI_PHYSICAL_ADDRESS AllocAddress;\r
26 VOID *HostAddress;\r
27 EFI_PCI_IO_PROTOCOL_OPERATION Operation;\r
28 UINTN NumberOfBytes;\r
29} NON_DISCOVERABLE_PCI_DEVICE_MAP_INFO;\r
30\r
31//\r
32// Get the resource associated with BAR number 'BarIndex'.\r
33//\r
34STATIC\r
35EFI_STATUS\r
36GetBarResource (\r
37 IN NON_DISCOVERABLE_PCI_DEVICE *Dev,\r
38 IN UINT8 BarIndex,\r
39 OUT EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR **Descriptor\r
40 )\r
41{\r
42 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Desc;\r
43\r
44 if (BarIndex < Dev->BarOffset) {\r
45 return EFI_NOT_FOUND;\r
46 }\r
47\r
8b78de74 48 BarIndex -= (UINT8)Dev->BarOffset;\r
a42e6d44
AB
49\r
50 for (Desc = Dev->Device->Resources;\r
51 Desc->Desc != ACPI_END_TAG_DESCRIPTOR;\r
52 Desc = (VOID *)((UINT8 *)Desc + Desc->Len + 3)) {\r
53\r
54 if (BarIndex == 0) {\r
55 *Descriptor = Desc;\r
56 return EFI_SUCCESS;\r
57 }\r
58\r
59 BarIndex -= 1;\r
60 }\r
61 return EFI_NOT_FOUND;\r
62}\r
63\r
64STATIC\r
65EFI_STATUS\r
8b78de74 66EFIAPI\r
a42e6d44
AB
67PciIoPollMem (\r
68 IN EFI_PCI_IO_PROTOCOL *This,\r
69 IN EFI_PCI_IO_PROTOCOL_WIDTH Width,\r
70 IN UINT8 BarIndex,\r
71 IN UINT64 Offset,\r
72 IN UINT64 Mask,\r
73 IN UINT64 Value,\r
74 IN UINT64 Delay,\r
75 OUT UINT64 *Result\r
76 )\r
77{\r
78 ASSERT (FALSE);\r
79 return EFI_UNSUPPORTED;\r
80}\r
81\r
82STATIC\r
83EFI_STATUS\r
8b78de74 84EFIAPI\r
a42e6d44
AB
85PciIoPollIo (\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
100STATIC\r
101EFI_STATUS\r
8b78de74 102EFIAPI\r
a42e6d44
AB
103PciIoMemRW (\r
104 IN EFI_PCI_IO_PROTOCOL_WIDTH Width,\r
105 IN UINTN Count,\r
106 IN UINTN DstStride,\r
107 IN VOID *Dst,\r
108 IN UINTN SrcStride,\r
109 OUT CONST VOID *Src\r
110 )\r
111{\r
112 volatile UINT8 *Dst8;\r
113 volatile UINT16 *Dst16;\r
114 volatile UINT32 *Dst32;\r
115 volatile CONST UINT8 *Src8;\r
116 volatile CONST UINT16 *Src16;\r
117 volatile CONST UINT32 *Src32;\r
118\r
119 //\r
120 // Loop for each iteration and move the data\r
121 //\r
122 switch (Width & 0x3) {\r
123 case EfiPciWidthUint8:\r
124 Dst8 = (UINT8 *)Dst;\r
125 Src8 = (UINT8 *)Src;\r
126 for (;Count > 0; Count--, Dst8 += DstStride, Src8 += SrcStride) {\r
127 *Dst8 = *Src8;\r
128 }\r
129 break;\r
130 case EfiPciWidthUint16:\r
131 Dst16 = (UINT16 *)Dst;\r
132 Src16 = (UINT16 *)Src;\r
133 for (;Count > 0; Count--, Dst16 += DstStride, Src16 += SrcStride) {\r
134 *Dst16 = *Src16;\r
135 }\r
136 break;\r
137 case EfiPciWidthUint32:\r
138 Dst32 = (UINT32 *)Dst;\r
139 Src32 = (UINT32 *)Src;\r
140 for (;Count > 0; Count--, Dst32 += DstStride, Src32 += SrcStride) {\r
141 *Dst32 = *Src32;\r
142 }\r
143 break;\r
144 default:\r
145 return EFI_INVALID_PARAMETER;\r
146 }\r
147\r
148 return EFI_SUCCESS;\r
149}\r
150\r
151STATIC\r
152EFI_STATUS\r
8b78de74 153EFIAPI\r
a42e6d44
AB
154PciIoMemRead (\r
155 IN EFI_PCI_IO_PROTOCOL *This,\r
156 IN EFI_PCI_IO_PROTOCOL_WIDTH Width,\r
157 IN UINT8 BarIndex,\r
158 IN UINT64 Offset,\r
159 IN UINTN Count,\r
160 IN OUT VOID *Buffer\r
161 )\r
162{\r
163 NON_DISCOVERABLE_PCI_DEVICE *Dev;\r
164 UINTN AlignMask;\r
165 VOID *Address;\r
166 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Desc;\r
167 EFI_STATUS Status;\r
168\r
169 if (Buffer == NULL) {\r
170 return EFI_INVALID_PARAMETER;\r
171 }\r
172\r
173 Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);\r
174\r
175 //\r
176 // Only allow accesses to the BARs we emulate\r
177 //\r
178 Status = GetBarResource (Dev, BarIndex, &Desc);\r
179 if (EFI_ERROR (Status)) {\r
180 return Status;\r
181 }\r
182\r
183 if (Offset + (Count << (Width & 0x3)) > Desc->AddrLen) {\r
184 return EFI_UNSUPPORTED;\r
185 }\r
186\r
187 Address = (VOID *)(UINTN)(Desc->AddrRangeMin + Offset);\r
188 AlignMask = (1 << (Width & 0x03)) - 1;\r
189 if ((UINTN)Address & AlignMask) {\r
190 return EFI_INVALID_PARAMETER;\r
191 }\r
192\r
193 switch (Width) {\r
82bf462e
HW
194 case EfiPciIoWidthUint8:\r
195 case EfiPciIoWidthUint16:\r
196 case EfiPciIoWidthUint32:\r
197 case EfiPciIoWidthUint64:\r
a42e6d44
AB
198 return PciIoMemRW (Width, Count, 1, Buffer, 1, Address);\r
199\r
82bf462e
HW
200 case EfiPciIoWidthFifoUint8:\r
201 case EfiPciIoWidthFifoUint16:\r
202 case EfiPciIoWidthFifoUint32:\r
203 case EfiPciIoWidthFifoUint64:\r
a42e6d44
AB
204 return PciIoMemRW (Width, Count, 1, Buffer, 0, Address);\r
205\r
82bf462e
HW
206 case EfiPciIoWidthFillUint8:\r
207 case EfiPciIoWidthFillUint16:\r
208 case EfiPciIoWidthFillUint32:\r
209 case EfiPciIoWidthFillUint64:\r
a42e6d44
AB
210 return PciIoMemRW (Width, Count, 0, Buffer, 1, Address);\r
211\r
212 default:\r
213 break;\r
214 }\r
215 return EFI_INVALID_PARAMETER;\r
216}\r
217\r
218STATIC\r
219EFI_STATUS\r
8b78de74 220EFIAPI\r
a42e6d44
AB
221PciIoMemWrite (\r
222 IN EFI_PCI_IO_PROTOCOL *This,\r
223 IN EFI_PCI_IO_PROTOCOL_WIDTH Width,\r
224 IN UINT8 BarIndex,\r
225 IN UINT64 Offset,\r
226 IN UINTN Count,\r
227 IN OUT VOID *Buffer\r
228 )\r
229{\r
230 NON_DISCOVERABLE_PCI_DEVICE *Dev;\r
231 UINTN AlignMask;\r
232 VOID *Address;\r
233 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Desc;\r
234 EFI_STATUS Status;\r
235\r
236 if (Buffer == NULL) {\r
237 return EFI_INVALID_PARAMETER;\r
238 }\r
239\r
240 Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);\r
241\r
242 //\r
243 // Only allow accesses to the BARs we emulate\r
244 //\r
245 Status = GetBarResource (Dev, BarIndex, &Desc);\r
246 if (EFI_ERROR (Status)) {\r
247 return Status;\r
248 }\r
249\r
250 if (Offset + (Count << (Width & 0x3)) > Desc->AddrLen) {\r
251 return EFI_UNSUPPORTED;\r
252 }\r
253\r
254 Address = (VOID *)(UINTN)(Desc->AddrRangeMin + Offset);\r
255 AlignMask = (1 << (Width & 0x03)) - 1;\r
256 if ((UINTN)Address & AlignMask) {\r
257 return EFI_INVALID_PARAMETER;\r
258 }\r
259\r
260 switch (Width) {\r
82bf462e
HW
261 case EfiPciIoWidthUint8:\r
262 case EfiPciIoWidthUint16:\r
263 case EfiPciIoWidthUint32:\r
264 case EfiPciIoWidthUint64:\r
a42e6d44
AB
265 return PciIoMemRW (Width, Count, 1, Address, 1, Buffer);\r
266\r
82bf462e
HW
267 case EfiPciIoWidthFifoUint8:\r
268 case EfiPciIoWidthFifoUint16:\r
269 case EfiPciIoWidthFifoUint32:\r
270 case EfiPciIoWidthFifoUint64:\r
a42e6d44
AB
271 return PciIoMemRW (Width, Count, 0, Address, 1, Buffer);\r
272\r
82bf462e
HW
273 case EfiPciIoWidthFillUint8:\r
274 case EfiPciIoWidthFillUint16:\r
275 case EfiPciIoWidthFillUint32:\r
276 case EfiPciIoWidthFillUint64:\r
a42e6d44
AB
277 return PciIoMemRW (Width, Count, 1, Address, 0, Buffer);\r
278\r
279 default:\r
280 break;\r
281 }\r
282 return EFI_INVALID_PARAMETER;\r
283}\r
284\r
285STATIC\r
286EFI_STATUS\r
8b78de74 287EFIAPI\r
a42e6d44
AB
288PciIoIoRead (\r
289 IN EFI_PCI_IO_PROTOCOL *This,\r
290 IN EFI_PCI_IO_PROTOCOL_WIDTH Width,\r
291 IN UINT8 BarIndex,\r
292 IN UINT64 Offset,\r
293 IN UINTN Count,\r
294 IN OUT VOID *Buffer\r
295 )\r
296{\r
297 ASSERT (FALSE);\r
298 return EFI_UNSUPPORTED;\r
299}\r
300\r
301STATIC\r
302EFI_STATUS\r
8b78de74 303EFIAPI\r
a42e6d44
AB
304PciIoIoWrite (\r
305 IN EFI_PCI_IO_PROTOCOL *This,\r
306 IN EFI_PCI_IO_PROTOCOL_WIDTH Width,\r
307 IN UINT8 BarIndex,\r
308 IN UINT64 Offset,\r
309 IN UINTN Count,\r
310 IN OUT VOID *Buffer\r
311 )\r
312{\r
313 ASSERT (FALSE);\r
314 return EFI_UNSUPPORTED;\r
315}\r
316\r
317STATIC\r
318EFI_STATUS\r
8b78de74 319EFIAPI\r
a42e6d44
AB
320PciIoPciRead (\r
321 IN EFI_PCI_IO_PROTOCOL *This,\r
322 IN EFI_PCI_IO_PROTOCOL_WIDTH Width,\r
323 IN UINT32 Offset,\r
324 IN UINTN Count,\r
325 IN OUT VOID *Buffer\r
326 )\r
327{\r
328 NON_DISCOVERABLE_PCI_DEVICE *Dev;\r
329 VOID *Address;\r
330 UINTN Length;\r
331\r
332 if (Width < 0 || Width >= EfiPciIoWidthMaximum || Buffer == NULL) {\r
333 return EFI_INVALID_PARAMETER;\r
334 }\r
335\r
336 Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);\r
337 Address = (UINT8 *)&Dev->ConfigSpace + Offset;\r
338 Length = Count << ((UINTN)Width & 0x3);\r
339\r
340 if (Offset + Length > sizeof (Dev->ConfigSpace)) {\r
341 //\r
342 // Read all zeroes for config space accesses beyond the first\r
343 // 64 bytes\r
344 //\r
345 Length -= sizeof (Dev->ConfigSpace) - Offset;\r
346 ZeroMem ((UINT8 *)Buffer + sizeof (Dev->ConfigSpace) - Offset, Length);\r
347\r
348 Count -= Length >> ((UINTN)Width & 0x3);\r
349 }\r
350 return PciIoMemRW (Width, Count, 1, Buffer, 1, Address);\r
351}\r
352\r
353STATIC\r
354EFI_STATUS\r
8b78de74 355EFIAPI\r
a42e6d44
AB
356PciIoPciWrite (\r
357 IN EFI_PCI_IO_PROTOCOL *This,\r
358 IN EFI_PCI_IO_PROTOCOL_WIDTH Width,\r
359 IN UINT32 Offset,\r
360 IN UINTN Count,\r
361 IN OUT VOID *Buffer\r
362 )\r
363{\r
364 NON_DISCOVERABLE_PCI_DEVICE *Dev;\r
365 VOID *Address;\r
366\r
367 if (Width < 0 || Width >= EfiPciIoWidthMaximum || Buffer == NULL) {\r
368 return EFI_INVALID_PARAMETER;\r
369 }\r
370\r
371 Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);\r
372 Address = (UINT8 *)&Dev->ConfigSpace + Offset;\r
373\r
374 if (Offset + (Count << ((UINTN)Width & 0x3)) > sizeof (Dev->ConfigSpace)) {\r
375 return EFI_UNSUPPORTED;\r
376 }\r
377\r
378 return PciIoMemRW (Width, Count, 1, Address, 1, Buffer);\r
379}\r
380\r
381STATIC\r
382EFI_STATUS\r
8b78de74 383EFIAPI\r
a42e6d44
AB
384PciIoCopyMem (\r
385 IN EFI_PCI_IO_PROTOCOL *This,\r
386 IN EFI_PCI_IO_PROTOCOL_WIDTH Width,\r
387 IN UINT8 DestBarIndex,\r
388 IN UINT64 DestOffset,\r
389 IN UINT8 SrcBarIndex,\r
390 IN UINT64 SrcOffset,\r
391 IN UINTN Count\r
392 )\r
393{\r
394 ASSERT (FALSE);\r
395 return EFI_UNSUPPORTED;\r
396}\r
397\r
398STATIC\r
399EFI_STATUS\r
8b78de74 400EFIAPI\r
a42e6d44
AB
401CoherentPciIoMap (\r
402 IN EFI_PCI_IO_PROTOCOL *This,\r
403 IN EFI_PCI_IO_PROTOCOL_OPERATION Operation,\r
404 IN VOID *HostAddress,\r
405 IN OUT UINTN *NumberOfBytes,\r
406 OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,\r
407 OUT VOID **Mapping\r
408 )\r
409{\r
410 NON_DISCOVERABLE_PCI_DEVICE *Dev;\r
411 EFI_STATUS Status;\r
412 NON_DISCOVERABLE_PCI_DEVICE_MAP_INFO *MapInfo;\r
413\r
414 //\r
415 // If HostAddress exceeds 4 GB, and this device does not support 64-bit DMA\r
416 // addressing, we need to allocate a bounce buffer and copy over the data.\r
417 //\r
418 Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);\r
419 if ((Dev->Attributes & EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE) == 0 &&\r
420 (UINTN)HostAddress + *NumberOfBytes > SIZE_4GB) {\r
421\r
422 //\r
423 // Bounce buffering is not possible for consistent mappings\r
424 //\r
425 if (Operation == EfiPciIoOperationBusMasterCommonBuffer) {\r
426 return EFI_UNSUPPORTED;\r
427 }\r
428\r
429 MapInfo = AllocatePool (sizeof *MapInfo);\r
430 if (MapInfo == NULL) {\r
431 return EFI_OUT_OF_RESOURCES;\r
432 }\r
433\r
434 MapInfo->AllocAddress = MAX_UINT32;\r
435 MapInfo->HostAddress = HostAddress;\r
436 MapInfo->Operation = Operation;\r
437 MapInfo->NumberOfBytes = *NumberOfBytes;\r
438\r
439 Status = gBS->AllocatePages (AllocateMaxAddress, EfiBootServicesData,\r
440 EFI_SIZE_TO_PAGES (MapInfo->NumberOfBytes),\r
441 &MapInfo->AllocAddress);\r
442 if (EFI_ERROR (Status)) {\r
443 //\r
444 // If we fail here, it is likely because the system has no memory below\r
445 // 4 GB to begin with. There is not much we can do about that other than\r
446 // fail the map request.\r
447 //\r
448 FreePool (MapInfo);\r
449 return EFI_DEVICE_ERROR;\r
450 }\r
451 if (Operation == EfiPciIoOperationBusMasterRead) {\r
452 gBS->CopyMem ((VOID *)(UINTN)MapInfo->AllocAddress, HostAddress,\r
453 *NumberOfBytes);\r
454 }\r
455 *DeviceAddress = MapInfo->AllocAddress;\r
456 *Mapping = MapInfo;\r
457 } else {\r
458 *DeviceAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress;\r
459 *Mapping = NULL;\r
460 }\r
461 return EFI_SUCCESS;\r
462}\r
463\r
464STATIC\r
465EFI_STATUS\r
8b78de74 466EFIAPI\r
a42e6d44
AB
467CoherentPciIoUnmap (\r
468 IN EFI_PCI_IO_PROTOCOL *This,\r
469 IN VOID *Mapping\r
470 )\r
471{\r
472 NON_DISCOVERABLE_PCI_DEVICE_MAP_INFO *MapInfo;\r
473\r
474 MapInfo = Mapping;\r
475 if (MapInfo != NULL) {\r
476 if (MapInfo->Operation == EfiPciIoOperationBusMasterWrite) {\r
477 gBS->CopyMem (MapInfo->HostAddress, (VOID *)(UINTN)MapInfo->AllocAddress,\r
478 MapInfo->NumberOfBytes);\r
479 }\r
480 gBS->FreePages (MapInfo->AllocAddress,\r
481 EFI_SIZE_TO_PAGES (MapInfo->NumberOfBytes));\r
482 FreePool (MapInfo);\r
483 }\r
484 return EFI_SUCCESS;\r
485}\r
486\r
487STATIC\r
488EFI_STATUS\r
8b78de74 489EFIAPI\r
a42e6d44
AB
490CoherentPciIoAllocateBuffer (\r
491 IN EFI_PCI_IO_PROTOCOL *This,\r
492 IN EFI_ALLOCATE_TYPE Type,\r
493 IN EFI_MEMORY_TYPE MemoryType,\r
494 IN UINTN Pages,\r
495 OUT VOID **HostAddress,\r
496 IN UINT64 Attributes\r
497 )\r
498{\r
499 NON_DISCOVERABLE_PCI_DEVICE *Dev;\r
500 EFI_PHYSICAL_ADDRESS AllocAddress;\r
501 EFI_ALLOCATE_TYPE AllocType;\r
502 EFI_STATUS Status;\r
503\r
504 if ((Attributes & ~(EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE |\r
505 EFI_PCI_ATTRIBUTE_MEMORY_CACHED)) != 0) {\r
506 return EFI_UNSUPPORTED;\r
507 }\r
508\r
509 //\r
510 // Allocate below 4 GB if the dual address cycle attribute has not\r
511 // been set. If the system has no memory available below 4 GB, there\r
512 // is little we can do except propagate the error.\r
513 //\r
514 Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);\r
515 if ((Dev->Attributes & EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE) == 0) {\r
516 AllocAddress = MAX_UINT32;\r
517 AllocType = AllocateMaxAddress;\r
518 } else {\r
519 AllocType = AllocateAnyPages;\r
520 }\r
521\r
522 Status = gBS->AllocatePages (AllocType, MemoryType, Pages, &AllocAddress);\r
523 if (!EFI_ERROR (Status)) {\r
524 *HostAddress = (VOID *)(UINTN)AllocAddress;\r
525 }\r
526 return Status;\r
527}\r
528\r
529STATIC\r
530EFI_STATUS\r
8b78de74 531EFIAPI\r
a42e6d44
AB
532CoherentPciIoFreeBuffer (\r
533 IN EFI_PCI_IO_PROTOCOL *This,\r
534 IN UINTN Pages,\r
535 IN VOID *HostAddress\r
536 )\r
537{\r
538 FreePages (HostAddress, Pages);\r
539 return EFI_SUCCESS;\r
540}\r
541\r
16296a12
AB
542STATIC\r
543EFI_STATUS\r
544EFIAPI\r
545NonCoherentPciIoFreeBuffer (\r
546 IN EFI_PCI_IO_PROTOCOL *This,\r
547 IN UINTN Pages,\r
548 IN VOID *HostAddress\r
549 )\r
550{\r
551 NON_DISCOVERABLE_PCI_DEVICE *Dev;\r
552 LIST_ENTRY *Entry;\r
553 EFI_STATUS Status;\r
554 NON_DISCOVERABLE_DEVICE_UNCACHED_ALLOCATION *Alloc;\r
555 BOOLEAN Found;\r
556\r
557 Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);\r
558\r
559 Found = FALSE;\r
560\r
561 //\r
562 // Find the uncached allocation list entry associated\r
563 // with this allocation\r
564 //\r
565 for (Entry = Dev->UncachedAllocationList.ForwardLink;\r
566 Entry != &Dev->UncachedAllocationList;\r
567 Entry = Entry->ForwardLink) {\r
568\r
569 Alloc = BASE_CR (Entry, NON_DISCOVERABLE_DEVICE_UNCACHED_ALLOCATION, List);\r
570 if (Alloc->HostAddress == HostAddress && Alloc->NumPages == Pages) {\r
571 //\r
572 // We are freeing the exact allocation we were given\r
573 // before by AllocateBuffer()\r
574 //\r
575 Found = TRUE;\r
576 break;\r
577 }\r
578 }\r
579\r
580 if (!Found) {\r
581 ASSERT_EFI_ERROR (EFI_NOT_FOUND);\r
582 return EFI_NOT_FOUND;\r
583 }\r
584\r
585 RemoveEntryList (&Alloc->List);\r
586\r
587 Status = gDS->SetMemorySpaceAttributes (\r
588 (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress,\r
589 EFI_PAGES_TO_SIZE (Pages),\r
590 Alloc->Attributes);\r
591 if (EFI_ERROR (Status)) {\r
592 goto FreeAlloc;\r
593 }\r
594\r
595 //\r
596 // If we fail to restore the original attributes, it is better to leak the\r
597 // memory than to return it to the heap\r
598 //\r
599 FreePages (HostAddress, Pages);\r
600\r
601FreeAlloc:\r
602 FreePool (Alloc);\r
603 return Status;\r
604}\r
605\r
606STATIC\r
607EFI_STATUS\r
608EFIAPI\r
609NonCoherentPciIoAllocateBuffer (\r
610 IN EFI_PCI_IO_PROTOCOL *This,\r
611 IN EFI_ALLOCATE_TYPE Type,\r
612 IN EFI_MEMORY_TYPE MemoryType,\r
613 IN UINTN Pages,\r
614 OUT VOID **HostAddress,\r
615 IN UINT64 Attributes\r
616 )\r
617{\r
618 NON_DISCOVERABLE_PCI_DEVICE *Dev;\r
619 EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor;\r
620 EFI_STATUS Status;\r
621 UINT64 MemType;\r
622 NON_DISCOVERABLE_DEVICE_UNCACHED_ALLOCATION *Alloc;\r
623 VOID *AllocAddress;\r
624\r
625 Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);\r
626\r
627 Status = CoherentPciIoAllocateBuffer (This, Type, MemoryType, Pages,\r
628 &AllocAddress, Attributes);\r
629 if (EFI_ERROR (Status)) {\r
630 return Status;\r
631 }\r
632\r
633 Status = gDS->GetMemorySpaceDescriptor (\r
634 (EFI_PHYSICAL_ADDRESS)(UINTN)AllocAddress,\r
635 &GcdDescriptor);\r
636 if (EFI_ERROR (Status)) {\r
637 goto FreeBuffer;\r
638 }\r
639\r
640 if ((GcdDescriptor.Capabilities & (EFI_MEMORY_WC | EFI_MEMORY_UC)) == 0) {\r
641 Status = EFI_UNSUPPORTED;\r
642 goto FreeBuffer;\r
643 }\r
644\r
645 //\r
646 // Set the preferred memory attributes\r
647 //\r
648 if ((Attributes & EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE) != 0 ||\r
649 (GcdDescriptor.Capabilities & EFI_MEMORY_UC) == 0) {\r
650 //\r
651 // Use write combining if it was requested, or if it is the only\r
652 // type supported by the region.\r
653 //\r
654 MemType = EFI_MEMORY_WC;\r
655 } else {\r
656 MemType = EFI_MEMORY_UC;\r
657 }\r
658\r
659 Alloc = AllocatePool (sizeof *Alloc);\r
660 if (Alloc == NULL) {\r
661 goto FreeBuffer;\r
662 }\r
663\r
664 Alloc->HostAddress = AllocAddress;\r
665 Alloc->NumPages = Pages;\r
666 Alloc->Attributes = GcdDescriptor.Attributes;\r
667\r
668 //\r
669 // Record this allocation in the linked list, so we\r
670 // can restore the memory space attributes later\r
671 //\r
672 InsertHeadList (&Dev->UncachedAllocationList, &Alloc->List);\r
673\r
674 Status = gDS->SetMemorySpaceAttributes (\r
675 (EFI_PHYSICAL_ADDRESS)(UINTN)AllocAddress,\r
676 EFI_PAGES_TO_SIZE (Pages),\r
677 MemType);\r
678 if (EFI_ERROR (Status)) {\r
679 goto RemoveList;\r
680 }\r
681\r
682 Status = mCpu->FlushDataCache (\r
683 mCpu,\r
684 (EFI_PHYSICAL_ADDRESS)(UINTN)AllocAddress,\r
685 EFI_PAGES_TO_SIZE (Pages),\r
686 EfiCpuFlushTypeInvalidate);\r
687 if (EFI_ERROR (Status)) {\r
688 goto RemoveList;\r
689 }\r
690\r
691 *HostAddress = AllocAddress;\r
692\r
693 return EFI_SUCCESS;\r
694\r
695RemoveList:\r
696 RemoveEntryList (&Alloc->List);\r
697 FreePool (Alloc);\r
698\r
699FreeBuffer:\r
700 CoherentPciIoFreeBuffer (This, Pages, AllocAddress);\r
701 return Status;\r
702}\r
703\r
704STATIC\r
705EFI_STATUS\r
706EFIAPI\r
707NonCoherentPciIoMap (\r
708 IN EFI_PCI_IO_PROTOCOL *This,\r
709 IN EFI_PCI_IO_PROTOCOL_OPERATION Operation,\r
710 IN VOID *HostAddress,\r
711 IN OUT UINTN *NumberOfBytes,\r
712 OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,\r
713 OUT VOID **Mapping\r
714 )\r
715{\r
716 NON_DISCOVERABLE_PCI_DEVICE *Dev;\r
717 EFI_STATUS Status;\r
718 NON_DISCOVERABLE_PCI_DEVICE_MAP_INFO *MapInfo;\r
719 UINTN AlignMask;\r
720 VOID *AllocAddress;\r
721 EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor;\r
722 BOOLEAN Bounce;\r
723\r
724 MapInfo = AllocatePool (sizeof *MapInfo);\r
725 if (MapInfo == NULL) {\r
726 return EFI_OUT_OF_RESOURCES;\r
727 }\r
728\r
729 MapInfo->HostAddress = HostAddress;\r
730 MapInfo->Operation = Operation;\r
731 MapInfo->NumberOfBytes = *NumberOfBytes;\r
732\r
733 Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);\r
734\r
735 //\r
736 // If this device does not support 64-bit DMA addressing, we need to allocate\r
737 // a bounce buffer and copy over the data in case HostAddress >= 4 GB.\r
738 //\r
739 Bounce = ((Dev->Attributes & EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE) == 0 &&\r
740 (UINTN)HostAddress + *NumberOfBytes > SIZE_4GB);\r
741\r
742 if (!Bounce) {\r
743 switch (Operation) {\r
744 case EfiPciIoOperationBusMasterRead:\r
745 case EfiPciIoOperationBusMasterWrite:\r
746 //\r
747 // For streaming DMA, it is sufficient if the buffer is aligned to\r
748 // the CPUs DMA buffer alignment.\r
749 //\r
750 AlignMask = mCpu->DmaBufferAlignment - 1;\r
751 if ((((UINTN) HostAddress | *NumberOfBytes) & AlignMask) == 0) {\r
752 break;\r
753 }\r
754 // fall through\r
755\r
756 case EfiPciIoOperationBusMasterCommonBuffer:\r
757 //\r
758 // Check whether the host address refers to an uncached mapping.\r
759 //\r
760 Status = gDS->GetMemorySpaceDescriptor (\r
761 (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress,\r
762 &GcdDescriptor);\r
763 if (EFI_ERROR (Status) ||\r
764 (GcdDescriptor.Attributes & (EFI_MEMORY_WB|EFI_MEMORY_WT)) != 0) {\r
765 Bounce = TRUE;\r
766 }\r
767 break;\r
768\r
769 default:\r
770 ASSERT (FALSE);\r
771 }\r
772 }\r
773\r
774 if (Bounce) {\r
775 if (Operation == EfiPciIoOperationBusMasterCommonBuffer) {\r
776 Status = EFI_DEVICE_ERROR;\r
777 goto FreeMapInfo;\r
778 }\r
779\r
780 Status = NonCoherentPciIoAllocateBuffer (This, AllocateAnyPages,\r
781 EfiBootServicesData, EFI_SIZE_TO_PAGES (MapInfo->NumberOfBytes),\r
782 &AllocAddress, EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE);\r
783 if (EFI_ERROR (Status)) {\r
784 goto FreeMapInfo;\r
785 }\r
786 MapInfo->AllocAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocAddress;\r
787 if (Operation == EfiPciIoOperationBusMasterRead) {\r
788 gBS->CopyMem (AllocAddress, HostAddress, *NumberOfBytes);\r
789 }\r
790 *DeviceAddress = MapInfo->AllocAddress;\r
791 } else {\r
792 MapInfo->AllocAddress = 0;\r
793 *DeviceAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress;\r
794\r
795 //\r
796 // We are not using a bounce buffer: the mapping is sufficiently\r
797 // aligned to allow us to simply flush the caches. Note that cleaning\r
798 // the caches is necessary for both data directions:\r
799 // - for bus master read, we want the latest data to be present\r
800 // in main memory\r
801 // - for bus master write, we don't want any stale dirty cachelines that\r
802 // may be written back unexpectedly, and clobber the data written to\r
803 // main memory by the device.\r
804 //\r
805 mCpu->FlushDataCache (mCpu, (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress,\r
806 *NumberOfBytes, EfiCpuFlushTypeWriteBack);\r
807 }\r
808\r
809 *Mapping = MapInfo;\r
810 return EFI_SUCCESS;\r
811\r
812FreeMapInfo:\r
813 FreePool (MapInfo);\r
814\r
815 return Status;\r
816}\r
817\r
818STATIC\r
819EFI_STATUS\r
820EFIAPI\r
821NonCoherentPciIoUnmap (\r
822 IN EFI_PCI_IO_PROTOCOL *This,\r
823 IN VOID *Mapping\r
824 )\r
825{\r
826 NON_DISCOVERABLE_PCI_DEVICE_MAP_INFO *MapInfo;\r
827\r
828 if (Mapping == NULL) {\r
829 return EFI_DEVICE_ERROR;\r
830 }\r
831\r
832 MapInfo = Mapping;\r
833 if (MapInfo->AllocAddress != 0) {\r
834 //\r
835 // We are using a bounce buffer: copy back the data if necessary,\r
836 // and free the buffer.\r
837 //\r
838 if (MapInfo->Operation == EfiPciIoOperationBusMasterWrite) {\r
839 gBS->CopyMem (MapInfo->HostAddress, (VOID *)(UINTN)MapInfo->AllocAddress,\r
840 MapInfo->NumberOfBytes);\r
841 }\r
842 NonCoherentPciIoFreeBuffer (This,\r
843 EFI_SIZE_TO_PAGES (MapInfo->NumberOfBytes),\r
844 (VOID *)(UINTN)MapInfo->AllocAddress);\r
845 } else {\r
846 //\r
847 // We are *not* using a bounce buffer: if this is a bus master write,\r
848 // we have to invalidate the caches so the CPU will see the uncached\r
849 // data written by the device.\r
850 //\r
851 if (MapInfo->Operation == EfiPciIoOperationBusMasterWrite) {\r
852 mCpu->FlushDataCache (mCpu,\r
853 (EFI_PHYSICAL_ADDRESS)(UINTN)MapInfo->HostAddress,\r
854 MapInfo->NumberOfBytes, EfiCpuFlushTypeInvalidate);\r
855 }\r
856 }\r
857 FreePool (MapInfo);\r
858 return EFI_SUCCESS;\r
859}\r
a42e6d44
AB
860\r
861STATIC\r
862EFI_STATUS\r
8b78de74 863EFIAPI\r
a42e6d44
AB
864PciIoFlush (\r
865 IN EFI_PCI_IO_PROTOCOL *This\r
866 )\r
867{\r
868 return EFI_SUCCESS;\r
869}\r
870\r
871STATIC\r
872EFI_STATUS\r
8b78de74 873EFIAPI\r
a42e6d44
AB
874PciIoGetLocation (\r
875 IN EFI_PCI_IO_PROTOCOL *This,\r
876 OUT UINTN *SegmentNumber,\r
877 OUT UINTN *BusNumber,\r
878 OUT UINTN *DeviceNumber,\r
879 OUT UINTN *FunctionNumber\r
880 )\r
881{\r
882 if (SegmentNumber == NULL ||\r
883 BusNumber == NULL ||\r
884 DeviceNumber == NULL ||\r
885 FunctionNumber == NULL) {\r
886 return EFI_INVALID_PARAMETER;\r
887 }\r
888\r
889 *SegmentNumber = 0;\r
890 *BusNumber = 0xff;\r
891 *DeviceNumber = 0;\r
892 *FunctionNumber = 0;\r
893\r
894 return EFI_SUCCESS;\r
895}\r
896\r
897STATIC\r
898EFI_STATUS\r
8b78de74 899EFIAPI\r
a42e6d44
AB
900PciIoAttributes (\r
901 IN EFI_PCI_IO_PROTOCOL *This,\r
902 IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION Operation,\r
903 IN UINT64 Attributes,\r
904 OUT UINT64 *Result OPTIONAL\r
905 )\r
906{\r
907 NON_DISCOVERABLE_PCI_DEVICE *Dev;\r
908 BOOLEAN Enable;\r
909\r
910 Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);\r
911\r
912 Enable = FALSE;\r
913 switch (Operation) {\r
914 case EfiPciIoAttributeOperationGet:\r
915 if (Result == NULL) {\r
916 return EFI_INVALID_PARAMETER;\r
917 }\r
918 *Result = Dev->Attributes;\r
919 break;\r
920\r
921 case EfiPciIoAttributeOperationSupported:\r
922 if (Result == NULL) {\r
923 return EFI_INVALID_PARAMETER;\r
924 }\r
925 *Result = EFI_PCI_DEVICE_ENABLE | EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE;\r
926 break;\r
927\r
928 case EfiPciIoAttributeOperationEnable:\r
929 Attributes |= Dev->Attributes;\r
930 case EfiPciIoAttributeOperationSet:\r
931 Enable = ((~Dev->Attributes & Attributes) & EFI_PCI_DEVICE_ENABLE) != 0;\r
932 Dev->Attributes = Attributes;\r
933 break;\r
934\r
935 case EfiPciIoAttributeOperationDisable:\r
936 Dev->Attributes &= ~Attributes;\r
937 break;\r
938\r
939 default:\r
940 return EFI_INVALID_PARAMETER;\r
941 };\r
942\r
943 //\r
944 // If we're setting any of the EFI_PCI_DEVICE_ENABLE bits, perform\r
945 // the device specific initialization now.\r
946 //\r
947 if (Enable && !Dev->Enabled && Dev->Device->Initialize != NULL) {\r
948 Dev->Device->Initialize (Dev->Device);\r
949 Dev->Enabled = TRUE;\r
950 }\r
951 return EFI_SUCCESS;\r
952}\r
953\r
954STATIC\r
955EFI_STATUS\r
8b78de74 956EFIAPI\r
a42e6d44
AB
957PciIoGetBarAttributes (\r
958 IN EFI_PCI_IO_PROTOCOL *This,\r
959 IN UINT8 BarIndex,\r
960 OUT UINT64 *Supports OPTIONAL,\r
961 OUT VOID **Resources OPTIONAL\r
962 )\r
963{\r
964 NON_DISCOVERABLE_PCI_DEVICE *Dev;\r
965 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor, *BarDesc;\r
966 EFI_ACPI_END_TAG_DESCRIPTOR *End;\r
967 EFI_STATUS Status;\r
968\r
969 if (Supports == NULL && Resources == NULL) {\r
970 return EFI_INVALID_PARAMETER;\r
971 }\r
972\r
973 Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);\r
974\r
975 Status = GetBarResource (Dev, BarIndex, &BarDesc);\r
976 if (EFI_ERROR (Status)) {\r
977 return Status;\r
978 }\r
979\r
980 //\r
981 // Don't expose any configurable attributes for our emulated BAR\r
982 //\r
983 if (Supports != NULL) {\r
984 *Supports = 0;\r
985 }\r
986\r
987 if (Resources != NULL) {\r
988 Descriptor = AllocatePool (sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) +\r
989 sizeof (EFI_ACPI_END_TAG_DESCRIPTOR));\r
990 if (Descriptor == NULL) {\r
991 return EFI_OUT_OF_RESOURCES;\r
992 }\r
993\r
994 CopyMem (Descriptor, BarDesc, sizeof *Descriptor);\r
995\r
996 End = (EFI_ACPI_END_TAG_DESCRIPTOR *) (Descriptor + 1);\r
997 End->Desc = ACPI_END_TAG_DESCRIPTOR;\r
998 End->Checksum = 0;\r
999\r
1000 *Resources = Descriptor;\r
1001 }\r
1002 return EFI_SUCCESS;\r
1003}\r
1004\r
1005STATIC\r
1006EFI_STATUS\r
8b78de74 1007EFIAPI\r
a42e6d44
AB
1008PciIoSetBarAttributes (\r
1009 IN EFI_PCI_IO_PROTOCOL *This,\r
1010 IN UINT64 Attributes,\r
1011 IN UINT8 BarIndex,\r
1012 IN OUT UINT64 *Offset,\r
1013 IN OUT UINT64 *Length\r
1014 )\r
1015{\r
1016 ASSERT (FALSE);\r
1017 return EFI_UNSUPPORTED;\r
1018}\r
1019\r
1020STATIC CONST EFI_PCI_IO_PROTOCOL PciIoTemplate =\r
1021{\r
1022 PciIoPollMem,\r
1023 PciIoPollIo,\r
1024 { PciIoMemRead, PciIoMemWrite },\r
1025 { PciIoIoRead, PciIoIoWrite },\r
1026 { PciIoPciRead, PciIoPciWrite },\r
1027 PciIoCopyMem,\r
1028 CoherentPciIoMap,\r
1029 CoherentPciIoUnmap,\r
1030 CoherentPciIoAllocateBuffer,\r
1031 CoherentPciIoFreeBuffer,\r
1032 PciIoFlush,\r
1033 PciIoGetLocation,\r
1034 PciIoAttributes,\r
1035 PciIoGetBarAttributes,\r
1036 PciIoSetBarAttributes,\r
1037 0,\r
1038 0\r
1039};\r
1040\r
1041VOID\r
1042InitializePciIoProtocol (\r
1043 NON_DISCOVERABLE_PCI_DEVICE *Dev\r
1044 )\r
1045{\r
1046 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Desc;\r
1047 INTN Idx;\r
1048\r
16296a12
AB
1049 InitializeListHead (&Dev->UncachedAllocationList);\r
1050\r
a42e6d44
AB
1051 Dev->ConfigSpace.Hdr.VendorId = PCI_ID_VENDOR_UNKNOWN;\r
1052 Dev->ConfigSpace.Hdr.DeviceId = PCI_ID_DEVICE_DONTCARE;\r
1053\r
1054 // Copy protocol structure\r
1055 CopyMem(&Dev->PciIo, &PciIoTemplate, sizeof PciIoTemplate);\r
1056\r
16296a12
AB
1057 if (Dev->Device->DmaType == NonDiscoverableDeviceDmaTypeNonCoherent) {\r
1058 Dev->PciIo.AllocateBuffer = NonCoherentPciIoAllocateBuffer;\r
1059 Dev->PciIo.FreeBuffer = NonCoherentPciIoFreeBuffer;\r
1060 Dev->PciIo.Map = NonCoherentPciIoMap;\r
1061 Dev->PciIo.Unmap = NonCoherentPciIoUnmap;\r
1062 }\r
1063\r
a42e6d44
AB
1064 if (CompareGuid (Dev->Device->Type, &gEdkiiNonDiscoverableAhciDeviceGuid)) {\r
1065 Dev->ConfigSpace.Hdr.ClassCode[0] = PCI_IF_MASS_STORAGE_AHCI;\r
1066 Dev->ConfigSpace.Hdr.ClassCode[1] = PCI_CLASS_MASS_STORAGE_SATADPA;\r
1067 Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_MASS_STORAGE;\r
1068 Dev->BarOffset = 5;\r
1069 } else if (CompareGuid (Dev->Device->Type,\r
1070 &gEdkiiNonDiscoverableEhciDeviceGuid)) {\r
1071 Dev->ConfigSpace.Hdr.ClassCode[0] = PCI_IF_EHCI;\r
1072 Dev->ConfigSpace.Hdr.ClassCode[1] = PCI_CLASS_SERIAL_USB;\r
1073 Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_SERIAL;\r
1074 Dev->BarOffset = 0;\r
1075 } else if (CompareGuid (Dev->Device->Type,\r
1076 &gEdkiiNonDiscoverableNvmeDeviceGuid)) {\r
1077 Dev->ConfigSpace.Hdr.ClassCode[0] = 0x2; // PCI_IF_NVMHCI\r
1078 Dev->ConfigSpace.Hdr.ClassCode[1] = 0x8; // PCI_CLASS_MASS_STORAGE_NVM\r
1079 Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_MASS_STORAGE;\r
1080 Dev->BarOffset = 0;\r
1081 } else if (CompareGuid (Dev->Device->Type,\r
1082 &gEdkiiNonDiscoverableOhciDeviceGuid)) {\r
1083 Dev->ConfigSpace.Hdr.ClassCode[0] = PCI_IF_OHCI;\r
1084 Dev->ConfigSpace.Hdr.ClassCode[1] = PCI_CLASS_SERIAL_USB;\r
1085 Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_SERIAL;\r
1086 Dev->BarOffset = 0;\r
1087 } else if (CompareGuid (Dev->Device->Type,\r
1088 &gEdkiiNonDiscoverableSdhciDeviceGuid)) {\r
1089 Dev->ConfigSpace.Hdr.ClassCode[0] = 0x0; // don't care\r
1090 Dev->ConfigSpace.Hdr.ClassCode[1] = PCI_SUBCLASS_SD_HOST_CONTROLLER;\r
1091 Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_SYSTEM_PERIPHERAL;\r
1092 Dev->BarOffset = 0;\r
1093 } else if (CompareGuid (Dev->Device->Type,\r
1094 &gEdkiiNonDiscoverableXhciDeviceGuid)) {\r
1095 Dev->ConfigSpace.Hdr.ClassCode[0] = PCI_IF_XHCI;\r
1096 Dev->ConfigSpace.Hdr.ClassCode[1] = PCI_CLASS_SERIAL_USB;\r
1097 Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_SERIAL;\r
1098 Dev->BarOffset = 0;\r
1099 } else if (CompareGuid (Dev->Device->Type,\r
1100 &gEdkiiNonDiscoverableUhciDeviceGuid)) {\r
1101 Dev->ConfigSpace.Hdr.ClassCode[0] = PCI_IF_UHCI;\r
1102 Dev->ConfigSpace.Hdr.ClassCode[1] = PCI_CLASS_SERIAL_USB;\r
1103 Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_SERIAL;\r
1104 Dev->BarOffset = 0;\r
1105 } else if (CompareGuid (Dev->Device->Type,\r
1106 &gEdkiiNonDiscoverableUfsDeviceGuid)) {\r
1107 Dev->ConfigSpace.Hdr.ClassCode[0] = 0x0; // don't care\r
1108 Dev->ConfigSpace.Hdr.ClassCode[1] = 0x9; // UFS controller subclass;\r
1109 Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_MASS_STORAGE;\r
1110 Dev->BarOffset = 0;\r
1111 } else {\r
1112 ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);\r
1113 }\r
1114\r
1115 //\r
1116 // Iterate over the resources to populate the virtual BARs\r
1117 //\r
1118 Idx = Dev->BarOffset;\r
1119 for (Desc = Dev->Device->Resources, Dev->BarCount = 0;\r
1120 Desc->Desc != ACPI_END_TAG_DESCRIPTOR;\r
1121 Desc = (VOID *)((UINT8 *)Desc + Desc->Len + 3)) {\r
1122\r
1123 ASSERT (Desc->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR);\r
1124 ASSERT (Desc->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM);\r
1125\r
1126 if (Idx >= PCI_MAX_BARS ||\r
1127 (Idx == PCI_MAX_BARS - 1 && Desc->AddrSpaceGranularity == 64)) {\r
1128 DEBUG ((DEBUG_ERROR,\r
1129 "%a: resource count exceeds number of emulated BARs\n",\r
1130 __FUNCTION__));\r
1131 ASSERT (FALSE);\r
1132 break;\r
1133 }\r
1134\r
1135 Dev->ConfigSpace.Device.Bar[Idx] = (UINT32)Desc->AddrRangeMin;\r
1136 Dev->BarCount++;\r
1137\r
1138 if (Desc->AddrSpaceGranularity == 64) {\r
1139 Dev->ConfigSpace.Device.Bar[Idx] |= 0x4;\r
1140 Dev->ConfigSpace.Device.Bar[++Idx] = (UINT32)RShiftU64 (\r
1141 Desc->AddrRangeMin, 32);\r
1142 }\r
1143 }\r
1144}\r