]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePciDeviceIo.c
MdeModulePkg/NonDiscoverablePciDeviceDxe: add support for non-coherent DMA
[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
561 //
562 // Find the uncached allocation list entry associated
563 // with this allocation
564 //
565 for (Entry = Dev->UncachedAllocationList.ForwardLink;
566 Entry != &Dev->UncachedAllocationList;
567 Entry = Entry->ForwardLink) {
568
569 Alloc = BASE_CR (Entry, NON_DISCOVERABLE_DEVICE_UNCACHED_ALLOCATION, List);
570 if (Alloc->HostAddress == HostAddress && Alloc->NumPages == Pages) {
571 //
572 // We are freeing the exact allocation we were given
573 // before by AllocateBuffer()
574 //
575 Found = TRUE;
576 break;
577 }
578 }
579
580 if (!Found) {
581 ASSERT_EFI_ERROR (EFI_NOT_FOUND);
582 return EFI_NOT_FOUND;
583 }
584
585 RemoveEntryList (&Alloc->List);
586
587 Status = gDS->SetMemorySpaceAttributes (
588 (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress,
589 EFI_PAGES_TO_SIZE (Pages),
590 Alloc->Attributes);
591 if (EFI_ERROR (Status)) {
592 goto FreeAlloc;
593 }
594
595 //
596 // If we fail to restore the original attributes, it is better to leak the
597 // memory than to return it to the heap
598 //
599 FreePages (HostAddress, Pages);
600
601 FreeAlloc:
602 FreePool (Alloc);
603 return Status;
604 }
605
606 STATIC
607 EFI_STATUS
608 EFIAPI
609 NonCoherentPciIoAllocateBuffer (
610 IN EFI_PCI_IO_PROTOCOL *This,
611 IN EFI_ALLOCATE_TYPE Type,
612 IN EFI_MEMORY_TYPE MemoryType,
613 IN UINTN Pages,
614 OUT VOID **HostAddress,
615 IN UINT64 Attributes
616 )
617 {
618 NON_DISCOVERABLE_PCI_DEVICE *Dev;
619 EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor;
620 EFI_STATUS Status;
621 UINT64 MemType;
622 NON_DISCOVERABLE_DEVICE_UNCACHED_ALLOCATION *Alloc;
623 VOID *AllocAddress;
624
625 Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);
626
627 Status = CoherentPciIoAllocateBuffer (This, Type, MemoryType, Pages,
628 &AllocAddress, Attributes);
629 if (EFI_ERROR (Status)) {
630 return Status;
631 }
632
633 Status = gDS->GetMemorySpaceDescriptor (
634 (EFI_PHYSICAL_ADDRESS)(UINTN)AllocAddress,
635 &GcdDescriptor);
636 if (EFI_ERROR (Status)) {
637 goto FreeBuffer;
638 }
639
640 if ((GcdDescriptor.Capabilities & (EFI_MEMORY_WC | EFI_MEMORY_UC)) == 0) {
641 Status = EFI_UNSUPPORTED;
642 goto FreeBuffer;
643 }
644
645 //
646 // Set the preferred memory attributes
647 //
648 if ((Attributes & EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE) != 0 ||
649 (GcdDescriptor.Capabilities & EFI_MEMORY_UC) == 0) {
650 //
651 // Use write combining if it was requested, or if it is the only
652 // type supported by the region.
653 //
654 MemType = EFI_MEMORY_WC;
655 } else {
656 MemType = EFI_MEMORY_UC;
657 }
658
659 Alloc = AllocatePool (sizeof *Alloc);
660 if (Alloc == NULL) {
661 goto FreeBuffer;
662 }
663
664 Alloc->HostAddress = AllocAddress;
665 Alloc->NumPages = Pages;
666 Alloc->Attributes = GcdDescriptor.Attributes;
667
668 //
669 // Record this allocation in the linked list, so we
670 // can restore the memory space attributes later
671 //
672 InsertHeadList (&Dev->UncachedAllocationList, &Alloc->List);
673
674 Status = gDS->SetMemorySpaceAttributes (
675 (EFI_PHYSICAL_ADDRESS)(UINTN)AllocAddress,
676 EFI_PAGES_TO_SIZE (Pages),
677 MemType);
678 if (EFI_ERROR (Status)) {
679 goto RemoveList;
680 }
681
682 Status = mCpu->FlushDataCache (
683 mCpu,
684 (EFI_PHYSICAL_ADDRESS)(UINTN)AllocAddress,
685 EFI_PAGES_TO_SIZE (Pages),
686 EfiCpuFlushTypeInvalidate);
687 if (EFI_ERROR (Status)) {
688 goto RemoveList;
689 }
690
691 *HostAddress = AllocAddress;
692
693 return EFI_SUCCESS;
694
695 RemoveList:
696 RemoveEntryList (&Alloc->List);
697 FreePool (Alloc);
698
699 FreeBuffer:
700 CoherentPciIoFreeBuffer (This, Pages, AllocAddress);
701 return Status;
702 }
703
704 STATIC
705 EFI_STATUS
706 EFIAPI
707 NonCoherentPciIoMap (
708 IN EFI_PCI_IO_PROTOCOL *This,
709 IN EFI_PCI_IO_PROTOCOL_OPERATION Operation,
710 IN VOID *HostAddress,
711 IN OUT UINTN *NumberOfBytes,
712 OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
713 OUT VOID **Mapping
714 )
715 {
716 NON_DISCOVERABLE_PCI_DEVICE *Dev;
717 EFI_STATUS Status;
718 NON_DISCOVERABLE_PCI_DEVICE_MAP_INFO *MapInfo;
719 UINTN AlignMask;
720 VOID *AllocAddress;
721 EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor;
722 BOOLEAN Bounce;
723
724 MapInfo = AllocatePool (sizeof *MapInfo);
725 if (MapInfo == NULL) {
726 return EFI_OUT_OF_RESOURCES;
727 }
728
729 MapInfo->HostAddress = HostAddress;
730 MapInfo->Operation = Operation;
731 MapInfo->NumberOfBytes = *NumberOfBytes;
732
733 Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);
734
735 //
736 // If this device does not support 64-bit DMA addressing, we need to allocate
737 // a bounce buffer and copy over the data in case HostAddress >= 4 GB.
738 //
739 Bounce = ((Dev->Attributes & EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE) == 0 &&
740 (UINTN)HostAddress + *NumberOfBytes > SIZE_4GB);
741
742 if (!Bounce) {
743 switch (Operation) {
744 case EfiPciIoOperationBusMasterRead:
745 case EfiPciIoOperationBusMasterWrite:
746 //
747 // For streaming DMA, it is sufficient if the buffer is aligned to
748 // the CPUs DMA buffer alignment.
749 //
750 AlignMask = mCpu->DmaBufferAlignment - 1;
751 if ((((UINTN) HostAddress | *NumberOfBytes) & AlignMask) == 0) {
752 break;
753 }
754 // fall through
755
756 case EfiPciIoOperationBusMasterCommonBuffer:
757 //
758 // Check whether the host address refers to an uncached mapping.
759 //
760 Status = gDS->GetMemorySpaceDescriptor (
761 (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress,
762 &GcdDescriptor);
763 if (EFI_ERROR (Status) ||
764 (GcdDescriptor.Attributes & (EFI_MEMORY_WB|EFI_MEMORY_WT)) != 0) {
765 Bounce = TRUE;
766 }
767 break;
768
769 default:
770 ASSERT (FALSE);
771 }
772 }
773
774 if (Bounce) {
775 if (Operation == EfiPciIoOperationBusMasterCommonBuffer) {
776 Status = EFI_DEVICE_ERROR;
777 goto FreeMapInfo;
778 }
779
780 Status = NonCoherentPciIoAllocateBuffer (This, AllocateAnyPages,
781 EfiBootServicesData, EFI_SIZE_TO_PAGES (MapInfo->NumberOfBytes),
782 &AllocAddress, EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE);
783 if (EFI_ERROR (Status)) {
784 goto FreeMapInfo;
785 }
786 MapInfo->AllocAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocAddress;
787 if (Operation == EfiPciIoOperationBusMasterRead) {
788 gBS->CopyMem (AllocAddress, HostAddress, *NumberOfBytes);
789 }
790 *DeviceAddress = MapInfo->AllocAddress;
791 } else {
792 MapInfo->AllocAddress = 0;
793 *DeviceAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress;
794
795 //
796 // We are not using a bounce buffer: the mapping is sufficiently
797 // aligned to allow us to simply flush the caches. Note that cleaning
798 // the caches is necessary for both data directions:
799 // - for bus master read, we want the latest data to be present
800 // in main memory
801 // - for bus master write, we don't want any stale dirty cachelines that
802 // may be written back unexpectedly, and clobber the data written to
803 // main memory by the device.
804 //
805 mCpu->FlushDataCache (mCpu, (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress,
806 *NumberOfBytes, EfiCpuFlushTypeWriteBack);
807 }
808
809 *Mapping = MapInfo;
810 return EFI_SUCCESS;
811
812 FreeMapInfo:
813 FreePool (MapInfo);
814
815 return Status;
816 }
817
818 STATIC
819 EFI_STATUS
820 EFIAPI
821 NonCoherentPciIoUnmap (
822 IN EFI_PCI_IO_PROTOCOL *This,
823 IN VOID *Mapping
824 )
825 {
826 NON_DISCOVERABLE_PCI_DEVICE_MAP_INFO *MapInfo;
827
828 if (Mapping == NULL) {
829 return EFI_DEVICE_ERROR;
830 }
831
832 MapInfo = Mapping;
833 if (MapInfo->AllocAddress != 0) {
834 //
835 // We are using a bounce buffer: copy back the data if necessary,
836 // and free the buffer.
837 //
838 if (MapInfo->Operation == EfiPciIoOperationBusMasterWrite) {
839 gBS->CopyMem (MapInfo->HostAddress, (VOID *)(UINTN)MapInfo->AllocAddress,
840 MapInfo->NumberOfBytes);
841 }
842 NonCoherentPciIoFreeBuffer (This,
843 EFI_SIZE_TO_PAGES (MapInfo->NumberOfBytes),
844 (VOID *)(UINTN)MapInfo->AllocAddress);
845 } else {
846 //
847 // We are *not* using a bounce buffer: if this is a bus master write,
848 // we have to invalidate the caches so the CPU will see the uncached
849 // data written by the device.
850 //
851 if (MapInfo->Operation == EfiPciIoOperationBusMasterWrite) {
852 mCpu->FlushDataCache (mCpu,
853 (EFI_PHYSICAL_ADDRESS)(UINTN)MapInfo->HostAddress,
854 MapInfo->NumberOfBytes, EfiCpuFlushTypeInvalidate);
855 }
856 }
857 FreePool (MapInfo);
858 return EFI_SUCCESS;
859 }
860
861 STATIC
862 EFI_STATUS
863 EFIAPI
864 PciIoFlush (
865 IN EFI_PCI_IO_PROTOCOL *This
866 )
867 {
868 return EFI_SUCCESS;
869 }
870
871 STATIC
872 EFI_STATUS
873 EFIAPI
874 PciIoGetLocation (
875 IN EFI_PCI_IO_PROTOCOL *This,
876 OUT UINTN *SegmentNumber,
877 OUT UINTN *BusNumber,
878 OUT UINTN *DeviceNumber,
879 OUT UINTN *FunctionNumber
880 )
881 {
882 if (SegmentNumber == NULL ||
883 BusNumber == NULL ||
884 DeviceNumber == NULL ||
885 FunctionNumber == NULL) {
886 return EFI_INVALID_PARAMETER;
887 }
888
889 *SegmentNumber = 0;
890 *BusNumber = 0xff;
891 *DeviceNumber = 0;
892 *FunctionNumber = 0;
893
894 return EFI_SUCCESS;
895 }
896
897 STATIC
898 EFI_STATUS
899 EFIAPI
900 PciIoAttributes (
901 IN EFI_PCI_IO_PROTOCOL *This,
902 IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION Operation,
903 IN UINT64 Attributes,
904 OUT UINT64 *Result OPTIONAL
905 )
906 {
907 NON_DISCOVERABLE_PCI_DEVICE *Dev;
908 BOOLEAN Enable;
909
910 Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);
911
912 Enable = FALSE;
913 switch (Operation) {
914 case EfiPciIoAttributeOperationGet:
915 if (Result == NULL) {
916 return EFI_INVALID_PARAMETER;
917 }
918 *Result = Dev->Attributes;
919 break;
920
921 case EfiPciIoAttributeOperationSupported:
922 if (Result == NULL) {
923 return EFI_INVALID_PARAMETER;
924 }
925 *Result = EFI_PCI_DEVICE_ENABLE | EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE;
926 break;
927
928 case EfiPciIoAttributeOperationEnable:
929 Attributes |= Dev->Attributes;
930 case EfiPciIoAttributeOperationSet:
931 Enable = ((~Dev->Attributes & Attributes) & EFI_PCI_DEVICE_ENABLE) != 0;
932 Dev->Attributes = Attributes;
933 break;
934
935 case EfiPciIoAttributeOperationDisable:
936 Dev->Attributes &= ~Attributes;
937 break;
938
939 default:
940 return EFI_INVALID_PARAMETER;
941 };
942
943 //
944 // If we're setting any of the EFI_PCI_DEVICE_ENABLE bits, perform
945 // the device specific initialization now.
946 //
947 if (Enable && !Dev->Enabled && Dev->Device->Initialize != NULL) {
948 Dev->Device->Initialize (Dev->Device);
949 Dev->Enabled = TRUE;
950 }
951 return EFI_SUCCESS;
952 }
953
954 STATIC
955 EFI_STATUS
956 EFIAPI
957 PciIoGetBarAttributes (
958 IN EFI_PCI_IO_PROTOCOL *This,
959 IN UINT8 BarIndex,
960 OUT UINT64 *Supports OPTIONAL,
961 OUT VOID **Resources OPTIONAL
962 )
963 {
964 NON_DISCOVERABLE_PCI_DEVICE *Dev;
965 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor, *BarDesc;
966 EFI_ACPI_END_TAG_DESCRIPTOR *End;
967 EFI_STATUS Status;
968
969 if (Supports == NULL && Resources == NULL) {
970 return EFI_INVALID_PARAMETER;
971 }
972
973 Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);
974
975 Status = GetBarResource (Dev, BarIndex, &BarDesc);
976 if (EFI_ERROR (Status)) {
977 return Status;
978 }
979
980 //
981 // Don't expose any configurable attributes for our emulated BAR
982 //
983 if (Supports != NULL) {
984 *Supports = 0;
985 }
986
987 if (Resources != NULL) {
988 Descriptor = AllocatePool (sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) +
989 sizeof (EFI_ACPI_END_TAG_DESCRIPTOR));
990 if (Descriptor == NULL) {
991 return EFI_OUT_OF_RESOURCES;
992 }
993
994 CopyMem (Descriptor, BarDesc, sizeof *Descriptor);
995
996 End = (EFI_ACPI_END_TAG_DESCRIPTOR *) (Descriptor + 1);
997 End->Desc = ACPI_END_TAG_DESCRIPTOR;
998 End->Checksum = 0;
999
1000 *Resources = Descriptor;
1001 }
1002 return EFI_SUCCESS;
1003 }
1004
1005 STATIC
1006 EFI_STATUS
1007 EFIAPI
1008 PciIoSetBarAttributes (
1009 IN EFI_PCI_IO_PROTOCOL *This,
1010 IN UINT64 Attributes,
1011 IN UINT8 BarIndex,
1012 IN OUT UINT64 *Offset,
1013 IN OUT UINT64 *Length
1014 )
1015 {
1016 ASSERT (FALSE);
1017 return EFI_UNSUPPORTED;
1018 }
1019
1020 STATIC CONST EFI_PCI_IO_PROTOCOL PciIoTemplate =
1021 {
1022 PciIoPollMem,
1023 PciIoPollIo,
1024 { PciIoMemRead, PciIoMemWrite },
1025 { PciIoIoRead, PciIoIoWrite },
1026 { PciIoPciRead, PciIoPciWrite },
1027 PciIoCopyMem,
1028 CoherentPciIoMap,
1029 CoherentPciIoUnmap,
1030 CoherentPciIoAllocateBuffer,
1031 CoherentPciIoFreeBuffer,
1032 PciIoFlush,
1033 PciIoGetLocation,
1034 PciIoAttributes,
1035 PciIoGetBarAttributes,
1036 PciIoSetBarAttributes,
1037 0,
1038 0
1039 };
1040
1041 VOID
1042 InitializePciIoProtocol (
1043 NON_DISCOVERABLE_PCI_DEVICE *Dev
1044 )
1045 {
1046 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Desc;
1047 INTN Idx;
1048
1049 InitializeListHead (&Dev->UncachedAllocationList);
1050
1051 Dev->ConfigSpace.Hdr.VendorId = PCI_ID_VENDOR_UNKNOWN;
1052 Dev->ConfigSpace.Hdr.DeviceId = PCI_ID_DEVICE_DONTCARE;
1053
1054 // Copy protocol structure
1055 CopyMem(&Dev->PciIo, &PciIoTemplate, sizeof PciIoTemplate);
1056
1057 if (Dev->Device->DmaType == NonDiscoverableDeviceDmaTypeNonCoherent) {
1058 Dev->PciIo.AllocateBuffer = NonCoherentPciIoAllocateBuffer;
1059 Dev->PciIo.FreeBuffer = NonCoherentPciIoFreeBuffer;
1060 Dev->PciIo.Map = NonCoherentPciIoMap;
1061 Dev->PciIo.Unmap = NonCoherentPciIoUnmap;
1062 }
1063
1064 if (CompareGuid (Dev->Device->Type, &gEdkiiNonDiscoverableAhciDeviceGuid)) {
1065 Dev->ConfigSpace.Hdr.ClassCode[0] = PCI_IF_MASS_STORAGE_AHCI;
1066 Dev->ConfigSpace.Hdr.ClassCode[1] = PCI_CLASS_MASS_STORAGE_SATADPA;
1067 Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_MASS_STORAGE;
1068 Dev->BarOffset = 5;
1069 } else if (CompareGuid (Dev->Device->Type,
1070 &gEdkiiNonDiscoverableEhciDeviceGuid)) {
1071 Dev->ConfigSpace.Hdr.ClassCode[0] = PCI_IF_EHCI;
1072 Dev->ConfigSpace.Hdr.ClassCode[1] = PCI_CLASS_SERIAL_USB;
1073 Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_SERIAL;
1074 Dev->BarOffset = 0;
1075 } else if (CompareGuid (Dev->Device->Type,
1076 &gEdkiiNonDiscoverableNvmeDeviceGuid)) {
1077 Dev->ConfigSpace.Hdr.ClassCode[0] = 0x2; // PCI_IF_NVMHCI
1078 Dev->ConfigSpace.Hdr.ClassCode[1] = 0x8; // PCI_CLASS_MASS_STORAGE_NVM
1079 Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_MASS_STORAGE;
1080 Dev->BarOffset = 0;
1081 } else if (CompareGuid (Dev->Device->Type,
1082 &gEdkiiNonDiscoverableOhciDeviceGuid)) {
1083 Dev->ConfigSpace.Hdr.ClassCode[0] = PCI_IF_OHCI;
1084 Dev->ConfigSpace.Hdr.ClassCode[1] = PCI_CLASS_SERIAL_USB;
1085 Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_SERIAL;
1086 Dev->BarOffset = 0;
1087 } else if (CompareGuid (Dev->Device->Type,
1088 &gEdkiiNonDiscoverableSdhciDeviceGuid)) {
1089 Dev->ConfigSpace.Hdr.ClassCode[0] = 0x0; // don't care
1090 Dev->ConfigSpace.Hdr.ClassCode[1] = PCI_SUBCLASS_SD_HOST_CONTROLLER;
1091 Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_SYSTEM_PERIPHERAL;
1092 Dev->BarOffset = 0;
1093 } else if (CompareGuid (Dev->Device->Type,
1094 &gEdkiiNonDiscoverableXhciDeviceGuid)) {
1095 Dev->ConfigSpace.Hdr.ClassCode[0] = PCI_IF_XHCI;
1096 Dev->ConfigSpace.Hdr.ClassCode[1] = PCI_CLASS_SERIAL_USB;
1097 Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_SERIAL;
1098 Dev->BarOffset = 0;
1099 } else if (CompareGuid (Dev->Device->Type,
1100 &gEdkiiNonDiscoverableUhciDeviceGuid)) {
1101 Dev->ConfigSpace.Hdr.ClassCode[0] = PCI_IF_UHCI;
1102 Dev->ConfigSpace.Hdr.ClassCode[1] = PCI_CLASS_SERIAL_USB;
1103 Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_SERIAL;
1104 Dev->BarOffset = 0;
1105 } else if (CompareGuid (Dev->Device->Type,
1106 &gEdkiiNonDiscoverableUfsDeviceGuid)) {
1107 Dev->ConfigSpace.Hdr.ClassCode[0] = 0x0; // don't care
1108 Dev->ConfigSpace.Hdr.ClassCode[1] = 0x9; // UFS controller subclass;
1109 Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_MASS_STORAGE;
1110 Dev->BarOffset = 0;
1111 } else {
1112 ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);
1113 }
1114
1115 //
1116 // Iterate over the resources to populate the virtual BARs
1117 //
1118 Idx = Dev->BarOffset;
1119 for (Desc = Dev->Device->Resources, Dev->BarCount = 0;
1120 Desc->Desc != ACPI_END_TAG_DESCRIPTOR;
1121 Desc = (VOID *)((UINT8 *)Desc + Desc->Len + 3)) {
1122
1123 ASSERT (Desc->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR);
1124 ASSERT (Desc->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM);
1125
1126 if (Idx >= PCI_MAX_BARS ||
1127 (Idx == PCI_MAX_BARS - 1 && Desc->AddrSpaceGranularity == 64)) {
1128 DEBUG ((DEBUG_ERROR,
1129 "%a: resource count exceeds number of emulated BARs\n",
1130 __FUNCTION__));
1131 ASSERT (FALSE);
1132 break;
1133 }
1134
1135 Dev->ConfigSpace.Device.Bar[Idx] = (UINT32)Desc->AddrRangeMin;
1136 Dev->BarCount++;
1137
1138 if (Desc->AddrSpaceGranularity == 64) {
1139 Dev->ConfigSpace.Device.Bar[Idx] |= 0x4;
1140 Dev->ConfigSpace.Device.Bar[++Idx] = (UINT32)RShiftU64 (
1141 Desc->AddrRangeMin, 32);
1142 }
1143 }
1144 }