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